1. 程式人生 > >[國家集訓隊] 部落戰爭

[國家集訓隊] 部落戰爭

pac print cstring 國家集訓隊 一次 總數 轉移 n) https

18.10.04模擬賽T2。

毒瘤出題人zzk祭出二分圖匹配,然而zwz還是A了......

事實證明zwz大佬是卡不住的。

洛谷 P2172 傳送門

首先如果每個點都放一個軍隊的話,總數就是城鎮的個數。

但是這樣的話就會很浪費。

從上到下,所有可轉移的點之間連邊,但是這道題要求每個點只能走一次,怎麽辦呢?

每個點只能走一次,每個人只能有一個對象,這不就是二分圖嗎(原諒我對二分圖的猥瑣見解)。

接下來就讓那些點亂搞對象匹配(原諒我對匈牙利算法的猥瑣見解)(原諒我的變量名cp)。

每有一個匹配,就節省一支軍隊。

最後就用總數減去匹配數就好了。

 1 #include<cstdio>
 2
#include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int m,n,r,c; 7 int d[55][55]; 8 int cp[2505],vis[2505]; 9 int dx[10],dy[10]; 10 int hd[2505],to[10005],nx[10005],ec; 11 int tot,ans; 12 13 int id(int x,int y) 14 { 15 return n*(x-1)+y; 16 } 17 18 void edge(int af,int at)
19 { 20 to[++ec]=at; 21 nx[ec]=hd[af]; 22 hd[af]=ec; 23 } 24 25 void add(int x,int y) 26 { 27 for(int i=1;i<=4;i++) 28 { 29 int tx=x+dx[i],ty=y+dy[i]; 30 if(tx<=0||tx>m||ty<=0||ty>n)continue; 31 if(!d[tx][ty]) 32 edge(id(tx,ty),id(x,y));
33 } 34 } 35 36 int ex(int p) 37 { 38 for(int i=hd[p];i;i=nx[i]) 39 { 40 int des=to[i]; 41 if(vis[des]!=tot) 42 { 43 vis[des]=tot; 44 if(!cp[des]||ex(cp[des])) 45 { 46 cp[des]=p; 47 return 1; 48 } 49 } 50 } 51 return 0; 52 } 53 54 void hungary() 55 { 56 for(int i=1;i<=m;i++) 57 { 58 for(int j=1;j<=n;j++) 59 { 60 if(d[i][j])continue; 61 tot++; 62 if(ex(id(i,j)))ans++; 63 } 64 } 65 } 66 67 int main() 68 { 69 scanf("%d%d%d%d",&m,&n,&r,&c); 70 dx[1]=dx[2]=-c,dx[3]=dx[4]=-r; 71 dy[1]=r,dy[2]=-r,dy[3]=c,dy[4]=-c; 72 for(int i=1;i<=m;i++) 73 { 74 char tmp[55]; 75 scanf("%s",tmp+1); 76 for(int j=1;j<=n;j++) 77 { 78 if(tmp[j]==x)d[i][j]=1; 79 else add(i,j); 80 } 81 } 82 hungary(); 83 printf("%d\n",tot-ans); 84 return 0; 85 }

[國家集訓隊] 部落戰爭