Description
Input
Output
Sample Input
2 3 3 2 1 0 1 2 2 5 3 1 2 3 3 3 1 0 1 2 2 5 3 1 2
Sample Output
Case #1: 3 Case #2: -1
Hint
Not all the cases are big ones.
思路:
首先要枚举区间,假设[l, r]是枚举的区间,最初l = r = 0。
当区间不满足炸毁条件时,增加r,直到满足条件。
当区间满足炸毁条件时,增加l,直到不满足条件。
同时记录国家的数量,可以减少验证的次数。
正确性很容易证明,因为排过序,所以遍历最近的符合条件肯定包含最优解
验证一段区间[l, r]是否满足可以炸毁K个以上城市:
利用树状DP,图就是国家间的特殊关系,因为可能是森林所以要把所有的根节点的值加起来。
dp[i][j]:能炸毁的最多的国家数目,i代表第几个节点,范围一定在[l, r]之内,j=0时不炸毁当前城市,j=1时炸毁当前城市。
叶子节点:dp[u][0] = 0, dp[u][1] = 1;
一般节点:
dp[u][0] = sum(max(dp[v][0], dp[v][1])); 因为不做选择所以完全不用考虑冲突。
dp[u][1] = sum(dp[v][0]) + 1; 选择u点就一定不能选择v点。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int mm=5e3+9; int c_to[mm],dp[mm][2]; class City { public:int x,who; bool operator<(const City&z)const { return x<z.x; } }city[mm]; int head[mm]; bool vis[mm]; class Edge { public:int v,next; }e[mm]; int cas,C,N,K,M,edge; void data() { memset(head,-1,sizeof(head)); edge=0; } void add(int u,int v) { e[edge].v=v;e[edge].next=head[u];head[u]=edge++; } void dfs(int u) { int v; vis[u]=1; dp[u][0]=0;//没选 dp[u][1]=1;///选择了,那肯定有一个国家就是本身 for(int i=head[u];~i;i=e[i].next) { v=e[i].v; if(!vis[v]&&c_to[v]) { dfs(v); dp[u][0]+=max(dp[v][0],dp[v][1]);///没选当前点,怎样都行 dp[u][1]+=dp[v][0];///选当前,则子节点不可选 } } } bool judge() { memset(vis,0,sizeof(vis)); int country_num=0; for(int i=1;i<=N;++i) if(!vis[i]&&c_to[i]) { dfs(i); country_num+=max(dp[i][0],dp[i][1]); } return country_num>=K; } int getans() { int l,r,num,ans=-1; l=r=0; sort(city,city+C);///城市坐标排序 memset(c_to,0,sizeof(c_to)); c_to[city[0].who]=1; num=1; while(l<C&&r<C) { bool flag=0; if(num>=K) { if(judge()) { flag=1; if(ans==-1) ans=city[r].x-city[l].x; else ans=min(ans,city[r].x-city[l].x); } } if(flag) { if(--c_to[city[l++].who]==0) --num; //printf("cc=%d %d\n",city[l].x,num); // puts("yes"); } else { if(!c_to[city[++r].who]) ++num; ++c_to[city[r].who]; } } return ans; } int main() { int u,v; while(~scanf("%d",&cas)) { for(int ca=1;ca<=cas;++ca) { printf("Case #%d: ",ca); scanf("%d%d%d%d",&C,&N,&K,&M); for(int i=0;i<C;++i) { scanf("%d%d",&city[i].x,&city[i].who); } data(); for(int i=0;i<M;++i) { scanf("%d%d",&u,&v); add(u,v);add(v,u); } printf("%d\n",getans()); } } return 0; }