BZOJ2088 POI2010 Teleportation


反省一下自己最近的狀況。

發現自己寫yy題和dp題的水平有所下降(本來就沒多高還掉,跟我昨天剛掉的CFrank一樣),最近幾天的比賽和寫題目都非常不順心。這幾天儘量突破逆境吧。


POI2010 題解整理

Description

大帝擁有n個星球,因爲距離非常遙遠,所以大帝在他所居住的1號星球和他的軍事基地霸中所在的2號星球建造了兩個傳送門,這樣從1號星球到2號星球就只需要250分鐘,回去也一樣(雙向)。

由於科技的發展,各個星球陸陸續續建造了和自己居民最經常去的星球之間的傳送門,並且他們的傳送門只需要1個小時(真快啊!),他們發現和別的星球建設傳送門對促進經濟發展有很大的幫助,於是向和其他所有星球建設傳送門發展。

大帝突然發現兩兩星球的傳送門的建設會威脅到他的安全,可是他又想促進自己帝國的發展,於是他請到了他精心培養的你,希望你能幫他解決這個難題。

Input

  • 第一行爲兩個由空格隔開的整數n(2n4104)m(0m106)n 表示星球數,m 表示其他星球已經建造的傳送門的對數(傳送門都是兩兩建造的,但不包括大帝在1號和2號的)。
  • 接下來m 行每行兩個由空格隔開的整數x,y(2x,y4104) ,表示這兩個星球建造了傳送門連接。

Sample Input

10 10
1 3
3 5
5 7
7 9
2 9
1 4
4 6
6 8
8 10
2 10

Input Details

這裏寫圖片描述

實線連接的是已經造好傳送門的兩星球,虛線連接表示可以增加建造的傳送門兩星球。

可以看出,建造了10對以後,從1號到2號星球還是大帝的1->2傳送門最快。

Output

  • 一個整數,表示還能讓多少對傳送門建造,但又不會比大帝從1號星球到2號星球快(就是說增加傳送門後,從1號星球到2號星球還是大帝的傳送門最快)。

Sample Output

10


思路轉自Spy大神。


Solution

首先我們可以將原圖作如下等效的變形:

這裏寫圖片描述 這裏寫圖片描述 這裏寫圖片描述

每一層都代表着該點最短到1和2的距離。有以下結論:

  • 顯然除了1,2外,其他點都會被分進這4層裏。那麼與1相連的,到1的最短距離爲2的點只能放在1,2層;與2相連的,到2的最短距離爲2的點只能放在4,3層。
  • 對於在某一層的點,它只能和本層與相鄰層的點連線,如果跨過一層連線,就會導致1,2的最短距離不是5了。
  • 其他剩餘沒有被扔進圖裏的點,將其視作第2,3層中某層的點。這樣首先是不會違背題意的,而且也更優:

    • 如果扔進第1層,那麼其增加的邊個數是size1+1+size2
    • 如果扔進第2層,那麼其增加的邊個數是size1+size2+size3

    顯然size31 ,所以扔進中間兩層更優。

  • 顯然增加的數值只會跟每層實際存在的點的個數有關,故可以枚舉有多少點進入2層,多少點進入3層,再計算即可。

Code :(基本轉自Spy大神)

#include <bits/stdc++.h>
#define M 40005
using namespace std;
typedef long long ll;
inline void Rd(int &res){
    res=0;char c;
    while(c=getchar(),c<48);
    do res=(res<<3)+(res<<1)+(c^48);
    while(c=getchar(),c>47);
}
vector<int>G[M];
int id[M],cnt[6],rcnt[6];
int main(){
    int n,m;Rd(n),Rd(m);
    for(int i=1;i<=m;i++){
        int u,v;
        Rd(u),Rd(v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    memset(id,-1,sizeof(id));
    id[1]=0,id[2]=5;

    for(int j=0;j<G[1].size();j++){
        int v=G[1][j];
        id[v]=1,cnt[id[v]]++;
    }
    for(int j=0;j<G[2].size();j++){
        int v=G[2][j];
        id[v]=4;cnt[id[v]]++;
    }
    for(int i=1;i<=n;i++)
        if(id[i]==1){
            for(int j=0;j<G[i].size();j++){
                int v=G[i][j];
                if(!id[v]){
                    id[v]=2;
                    cnt[id[v]]++;
                }
            }
        }else if(id[i]==4){
            for(int j=0;j<G[i].size();j++){
                int v=G[i][j];
                if(!id[v]){
                    id[v]=3;
                    cnt[id[v]]++;
                }
            }
        }
    int Cnt=0;
    for(int i=1;i<=n;i++)Cnt+=(id[i]==-1);//沒有分配到層的元素個數
//  printf("Cnt=%d\n",Cnt);
    rcnt[1]=cnt[1],rcnt[4]=cnt[4];
    int ans=0,res=rcnt[1]*(rcnt[1]-1)/2+rcnt[4]*(rcnt[4]-1)/2+1*rcnt[1]+rcnt[4]*1;
    for(int k=0;k<=Cnt;k++){
        rcnt[2]=cnt[2]+k,rcnt[3]=cnt[3]+Cnt-k;
        int tmp=rcnt[2]*(rcnt[2]-1)/2+rcnt[3]*(rcnt[3]-1)/2+
                rcnt[1]*rcnt[2]+rcnt[2]*rcnt[3]+rcnt[3]*rcnt[4];
        ans=max(tmp,ans);
    }
    cout<<ans+res-m<<endl;
}
發佈了48 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章