HDU 4354 Missile 树的最大独立集+枚举

来源:互联网 发布:郭靖黄蓉爱情知乎 编辑:程序博客网 时间:2024/05/21 15:47

题意:

在一条直线上有C个城市,分别属于N个国家,需要炸毁至少K个国家的城市,花费的金额为两端城市的距离,国家间有M个特殊关系,有关系的两个国家中最多只能摧毁一个国家的城市,关系没有传递性,求所需要的最小花费,如果无法完成输出-1。只能炸一次且不一定要炸掉线段上所有的城市。



解题思路:最先考虑的就是用什么模型了。
假如有a个国家,有的国家之间有边相连,问选哪些国家使得选中的国家之间没有边且国家数最多。
转化一下就是 最大独立集。
最大独立集能求的貌似只有二分图和树了,
题目中说了没有环存在,所以就用树上的最大独立集来求了。(近似于贪心,不会的网上找吧)


接下来就是枚举了,
枚举一个区间,区间里  最大独立集  就是在这个区间最多能炸掉的国家数。
如果最多能炸掉的国家数>=K的话,就说明这个区间满足要求了。


不过这里枚举也有技巧,如果是暴利枚举的话,O(N^2)的复杂度肯定TLE,
好在之前有过类似思路,能转化为O(N)的复杂度。(这种思路建议保留一下,很多优化中能用)
我的city是从0到c-1存的, 最开始给个边界值 l=0,r=0;
如果在(l,r)的区间满足条件,记录答案,并把l右移一位,
否则把r右移一位,
直到r==c结束。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#include <stack>using namespace std;#define FOR(i,l,r) for(int i=(l);i<=(r);++i)#define REP(i,n) for(int i=0;i<(n);++i)#define DSC(i,r,l) for(int i=(r);i>=(l);--i)#define N 2110#define M 2110#define INF 2000000000struct{    int to,next;}edge[M];int head[N],ip;bool visit[N],flag[N];void add(int u,int v){    edge[ip].to=v;edge[ip].next=head[u];head[u]=ip++;    edge[ip].to=u;edge[ip].next=head[v];head[v]=ip++;}struct Node{    int x;    int fa;    bool operator<(const Node a)const    {        return x<a.x;    }}node[5010];struct{    int x,y;}f[1010];void dfs(int pos,int pre,int &num)//贪心法求树上的最大独立集{    visit[pos]=0;    int to;    for(int p=head[pos];p!=-1;p=edge[p].next)    {        to=edge[p].to;        if(!visit[to]) continue;        dfs(to,pos,num);    }    if(!flag[pos])    {        flag[pos]=flag[pre]=1;        num++;    }}bool solve(int l,int r,int k,int m){    memset(visit,0,sizeof(visit));    memset(head,-1,sizeof(head)); ip=0;    memset(flag,0,sizeof(flag));    int num=0;    FOR(i,l,r) if(!visit[node[i].fa]) visit[node[i].fa]=1; //记录区间内存在的国家    REP(i,m)    {        if(visit[f[i].x] && visit[f[i].y] )        {            add(f[i].x,f[i].y);//在存在的国家间建边        }    }    FOR(i,l,r)    {        if(visit[ node[i].fa ]) dfs(node[i].fa,node[i].fa,num); //求每棵树上得最大独立集    }    if(num>=k)  return 1;    return 0;}int aaaa(int c,int n,int k,int m){    if(!solve(0,c-1,k,m)) return -1;    if(k<=1) return 0;//如果K<=1 ,随意炸掉一个城市就够了    int l=0,r=0;    int ans=2e9;    while(r<c)    {        if(solve(l,r,k,m))        {            ans=min(ans,node[r].x-node[l].x);            l++;        }        else r++;    }    return ans;}int main(){    int cas,cas1=1;    cin>>cas;    int c,n,k,m;    while(cas--)    {        cin>>c>>n>>k>>m;        REP(i,c)    scanf("%d%d",&node[i].x,&node[i].fa);        REP(i,m)    scanf("%d%d",&f[i].x,&f[i].y);        sort(node,node+c);//对原先的city按坐标排一次序        printf("Case #%d: %d\n",cas1++,aaaa(c,n,k,m));    }    return 0;}


原创粉丝点击