[国家集训队] 部落战争

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 }

 

posted @ 2018-10-05 09:21  cervusky  阅读(229)  评论(0编辑  收藏  举报

Contact with me