timus 1303. Minimal Coveragen URAL 解題報告 貪心或者DP
用最少的線段去覆蓋一個大區間,由於邊數最多
The set contains at least one and at most 99999 segments! 大區間最大0--5000,如果一般的DP的話可能超時,dp[i]表示如果用邊i的話覆蓋到當前位置所用的最少線段數目,如果成功覆蓋的話記錄最後所用的線段的編號,用k記錄! 也是N*N的算法,但是時間竟然沒卡主…… 神了, 當然這個題我沒用這個方法去做,因爲這個過了也是偶然,不明白爲什麼會被劃分到DP題組裏面,也許有更好的做法,但是到目前爲止還沒發現…… 網上搜不到DP解決的好辦法!
正規解法應該是劉汝佳書上的貪心做法!
貪心的話,就是先按照x升序排列,然後能覆蓋區間左端的前提下,儘可能使得y較大,然後從這個y爲區間的左端點繼續覆蓋知道覆蓋完……
這個題貌似可能有多種答案,應該用到特判……
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
#define LL long long
using namespace std;
const int N=100005;
const int INF=0x6fffffff;
struct node
{
int x,y;
}mem[N];
int f[N];
int sum[N];
int ans[N];
bool cmp(node a,node b)
{
if(a.x==b.x) return a.y>b.y;
return a.x<b.x;
}
void Fans(int l,int n)
{///???
for(int i=n;i>=1;--i)
{
ans[i]=l;
l=f[l];
}
}
int main()
{
//freopen("data","r",stdin);
int m;
int x,y;
scanf("%d",&m);
int I=0;
while(scanf("%d %d",&x,&y))
{
if(x==0&&y==0)
break;
if((x>=m&&y<=0)||(x==y))
continue;
mem[I].x=x;mem[I].y=y;++I;
}
sort(mem,mem+I,cmp);
memset(sum,-1,sizeof(sum));
int k=-1;
if(mem[0].x>0)
{
printf("No solution\n"); return 0;
}
int n=I;
I=0;
for(int i=0;i<n;++i)
{///把一些不必要的邊去掉
int l=0;
if(i>0&&mem[i].x!=mem[I-1].x)
for(l=0;l<I;++l)
{
if(mem[l].x<=mem[i].x&&mem[i].y<=mem[l].y)
break;
}
if(l==I)
{mem[I].x=mem[i].x;mem[I].y=mem[i].y;++I;}
}
for(int i=0;i<I;++i)
{
int x=mem[i].x;
int y=mem[i].y;
if(i>0&&x==mem[i-1].x)
continue;///根據已經排好的順序,x相同話y肯定是前面的大
if(x<=0)
{///???
sum[i]=1;
f[i]=-1;///第一條邊的父親當然是-1了
if(y>=m&&(k==-1||sum[i]<sum[k]))
{
k=i;///k記錄最少的sum的下標,最後根據這個來
}
}else
{
int temp=INF;int l=-1;
for(int j=0;j<i;++j)
{///仍然是一個O(n*n)的算法,竟然沒超時,數據是不是有點弱啊 邊數可是最多有10W條啊
if(sum[j]!=-1&&mem[j].y>=x&&sum[j]<temp)
{///sum[i]==-1表示邊i沒用
temp=sum[j];l=j;
}
}
if(l!=-1)
{
sum[i]=sum[l]+1;///急用
f[i]=l;///記錄父親
if(y>=m&&(k==-1||sum[i]<sum[k]))
{
k=i;///記錄用的最少的邊的號,前提是y>m也就說已經覆蓋完了,完了之後才能更新答案
}
}
}
}
if(k==-1)
printf("No solution\n");
else
{
printf("%d\n",sum[k]);
Fans(k,sum[k]);///尋找父親,路徑回溯啊!
for(int i=1;i<=sum[k];++i)
{
printf("%d %d\n",mem[ans[i]].x,mem[ans[i]].y);
}
}
return 0;
}