2014-2015 ACM-ICPC Moscow Subregional H - Holes 思維

題目鏈接: https://codeforces.com/gym/100519/problem/H

題意:

你現在有一個特殊的無向圖,這個圖除了最多某一個點外,其餘的點的度數均爲二,每個點上都有一隻兔子,現在災難要來了,你可以在 kk 個點上打洞,每隻兔子會往最近的洞跑,問你跑的最遠的兔子的最短距離是多少。

做法:

二分距離,重點是在已知當前距離 LL 情況下的判斷。

很明顯我們可以知道距離 LL 是個很特殊的距離,假如我們在中心點放一個點,那麼 LL 範圍內的點都可以被消除,並且我們只需要一個點,比較賺。

對於鏈的情況,在距離 LL 之外的範圍,我們可以確定一定都要放點的,所以我們就把這些必要的情況處理出來,並且將向外能延長的最長距離 maxlenmaxlen 記錄下來。(即可能在鏈上某一個點放上點,可以覆蓋到另外的點) 如果一條鏈的長度小於 maxlenmaxlen ,那麼我們這個時候甚至不需要在中心放點去覆蓋。

對於環的情況,如果我們要達到上述鏈的情況,就需要在兩邊都放點,還不如在中心點放一個點去覆蓋,有點不划算。 所以我們也就將必要的位置都先填上(即兩邊去掉 LL 之後的長度),並用儘可能平均的剩下的長度去和 maxlenmaxlenLL 比較。

最後看中心點是否被覆蓋到了來確定還要不要加點。

代碼

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define rep_e(i,u) for(int i=head[u];~i;i=nex[i])
using namespace std;
typedef long long ll;
const int maxn=1005;
const int maxm=maxn*maxn;
int de[maxn],n,m,k,rt,dep[maxn];
int head[maxn],to[maxm],nex[maxm],cnt;
vector<int> Link,Cir;
bool cmp(int a,int b){
    return a>b;
}
void add(int u,int v){
    to[cnt]=v;nex[cnt]=head[u];
    head[u]=cnt++;
}

int Gain_P(int L){
    int Ra=-1,flag=0,ret=0,mx=-1;
    int H=2*L+1;
    for(auto l: Link){
        if(l<=L) continue;
        int tmp=l-L;
        int need=tmp/H;
        tmp-=need*H;
        if(tmp){
            Ra=max(Ra,H-tmp-L-1);
        }
    }
    for(auto l: Link){
        if(l<=Ra) continue;
        if(l<=L) {
            flag=1; continue;
        }
        int tmp=l-L;
        int need=tmp/H;
        ret+=need;
        tmp-=need*H;
        if(tmp){
            ret++;
        }
        int res=tmp+L-(tmp?1:0)*H;
        if(res<=Ra) continue;
        else flag=1;
    }
    for(auto l:Cir){
        //printf("%d\n",l);
        int Le=(l+1)/2;
        if(Le<=Ra) continue;
        if(Le<=L) {
            flag=1; continue;
        }
        int tmp=l-2*L;
        int need=(tmp+H-1)/H;
        ret+=need;
        int res=l-need*H;
        if((res+1)/2<=Ra) continue;
        else {
            flag=1;
        }
    }
    if(Ra==-1) flag=1;
    return ret+flag;
}
int ck(int l){
    int P=Gain_P(l);
    //printf("l = %d P = %d\n",l,P);
    return P<=k;
}
void dfs(int u,int f,int d){
    dep[u]=d;
    int flag=0;
    rep_e(i,u){
        int v=to[i];
        if(v==f) continue;
        if(!dep[v]) dfs(v,u,d+1);
        else Cir.push_back(dep[v]-dep[u]);
        flag=1;
    }
    if(!flag) Link.push_back(dep[u]-1);
}
int main(){
    memset(head,-1,sizeof(head));
    scanf("%d%d%d",&n,&m,&k);

    rep(i,1,m){
        int x,y;scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
        de[x]++,de[y]++;
    }

    if(k==n) return 0*printf("0\n");
    rep(i,1,n) if(de[i]>2) rt=i;
    if(rt==0){
        int L=1,R=m,ans=-1;
        while(L<=R){
            int mid=L+R>>1;
            int M=mid*2+1;
            int ne=(n+M-1)/M;
            if(ne<=k){ ans=mid; R=mid-1;}
            else L=mid+1;
        }
        return 0*printf("%d\n",ans);
    }
    dfs(rt,-1,1);
    sort(Link.begin(),Link.end(),cmp);
    sort(Cir.begin(),Cir.end(),cmp);
    int L=1,R=m,ans=m;
    while(L<=R){
        int mid=(L+R)/2;
        if(ck(mid)){
            ans=mid; R=mid-1;
        }
        else L=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章