HDU 4354 Missile 樹的最大獨立集+枚舉

題意:

在一條直線上有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[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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章