[CODE FESTIVAL 2016]Distance Pairs
題意:有一個未知的邊權為$1$的圖,給定所有點到$1$的最短路$a_i$和到$2$的最短路$b_i$,問是否存在這樣的圖,如果存在,問圖中最少有多少條邊
先考慮$a_i$,有$a_1=0,a_i\neq0(i\neq1)$,對于一條邊$(x,y)$有$|a_x-a_y|\leq1$,對于任意$x\neq1$,存在$(x,y)$使得$a_x-1=a_y$,對$b_i$也有類似的約束
所以,我們將點$i$作為$(a_i,b_i)$畫在平面上,那么至少要有兩條邊:第一條連到$(a_i-1,b_i-1)$或$(a_i-1,b_i)$或$(a_i-1,b_i+1)$,第二條連到$(a_i-1,b_i-1)$或$(a_i,b_i-1)$或$(a_i+1,b_i-1)$,如果這時找不到可以連邊的點,那么就無解了(點$1$不用連第一種邊,點$2$不用連第二種邊)
如果可以連,那么我們構造出了一個有$2n-2$條邊的圖,顯然這個圖是滿足條件的
但我們要最小化圖中邊數,所以考慮尋找盡可能多的可以共用的邊
以下我們將第一種邊稱為$a$邊,第二種邊稱為$b$邊,共用邊只可能是兩種情況:1.對于點$i$,存在$(a_i-1,b_i-1)$,此時$i$的$a$邊和$b$邊可以共用;2.存在$i,j$使得$a_i-1=a_j,b_i+1=b_j$,此時$i$的$a$邊可以和$j$的$b$邊共用
我們把這$2n-2$條邊看成點,如果兩條邊可以共用,在代表它們的點之間連一條邊,求最大匹配即可,雖然是一般圖,但注意到只有那些滿足$a_i+b_i$相等的點$i$引出的邊才可能共用,所以建出來的圖是這樣的(圖來自官方題解)
圖中框代表某個坐標$(a_i,b_i)$上的點,紅點代表$b$邊,藍點代表$a$邊,如果方框內有連邊說明存在$(a_i-1,b_i-1)$
這種分層圖可以從左上往右下貪心選邊求最大匹配,實現時只需維護每個坐標的未匹配點個數即可
總時間復雜度為$O(n\log n)$,感覺這題還是不錯的
#include<stdio.h> #include<map> using namespace std; map<int,map<int,int> >mp,vis; int a[100010],b[100010]; bool ex(int x,int y){return mp.count(x)&&mp[x].count(y); } int main(){int n,i,j,s,las,now;scanf("%d",&n);#define wa {puts("-1");return 0;}for(i=1;i<=n;i++){scanf("%d%d",a+i,b+i);if(i!=1&&a[i]==0)waif(i!=2&&b[i]==0)wamp[a[i]][b[i]]++;}for(i=1;i<=n;i++){if(i!=2){if(!(ex(a[i]-1,b[i]-1)||ex(a[i],b[i]-1)||ex(a[i]+1,b[i]-1)))wa}if(i!=1){if(!(ex(a[i]-1,b[i]+1)||ex(a[i]-1,b[i])||ex(a[i]-1,b[i]-1)))wa}}s=0;for(i=1;i<=n;i++){if(!ex(a[i]-1,b[i]+1)&&!vis[a[i]][b[i]]){vis[a[i]][b[i]]=1;las=0;for(j=0;ex(a[i]+j,b[i]-j);j++){now=mp[a[i]+j][b[i]-j];s+=min(las,now);now-=min(las,now);if(ex(a[i]+j-1,b[i]-j-1)){s+=now;now=min(las,mp[a[i]+j][b[i]-j]);}elsenow=mp[a[i]+j][b[i]-j];las=now;}}}printf("%d",2*n-2-s); }轉載于:https://www.cnblogs.com/jefflyy/p/9744260.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的[CODE FESTIVAL 2016]Distance Pairs的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PostgreSQL 10.1 手册_部
- 下一篇: 洛谷 P2519 [HAOI2011]p