您的位置:首页 > 其它

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

2013-07-20 10:16 309 查看
题意:

在一条直线上有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 2000000000
struct
{
int to,next;
}edge[M];
int head
,ip;
bool visit
,flag
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: