【agc006f】Blackout

Description

给你一个n行n列的网格,第i行第j列的格子用(i,j)表示。

一开始的时候有m个格子被涂成黑色,其他的格子都是白色,具体一点,涂成黑色的格子为(a1,b1),(a2,b2),(a3,b3),…,(am,bm)。

你的目标是按照以下规则将尽可能多的白色格子涂成黑色:如果存在三个格子(x,y),(y,z),(z,x)满足(x,y)和(y,z)都是黑格子并且(z,x)是白格子(其中x,y,z都是[1,n]之间的整数),那么你可以将(z,x)涂成黑色。

输出你不能继续操作时,黑格子的最大数量。


Solution

我们可以将其转化为有向图,若存在(x,y)和(y,z)这两条边,则我们可以添加第三条边(z,x),求边的最大数量。

首先,各弱联通块之间互不影响,因此我们可以将各弱联通块分开考虑。

我们可以得到:

(1)一条长度为2的链可形成一个三元环。(x,y)(y,z)→(x,y)(y,z)(z,x) 

(2)一个二元环会形成自环。(x,y)(y,x)→(x,y)(y,x)(x,x)(y,y)

(3)所有连向自环点的点都会形成自环。(x,y)(y,y)→(x,y)(y,y)(y,x)(x,x)

(4)由(2)和(3)得若一个弱联通块存在二元环或自环,则该弱联通块可拓展为完全图。

我们考虑各弱联通块是否存在二元环或自环,用三种颜色进行染色(如三元环中三个点为不同的颜色),进行分类讨论:

(1)只出现了一种或两种颜色:说明该弱联通块无法添加新边;

(2)同一个点被染上两种或三种颜色:出现二元环或自环,该弱联通块可拓展为完全图;

(3)default:染色成功,染色为0的点连向染色为1的点,染色为1的点连向染色为2的点,染色为2的点连向染色为0的点。

Code

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 #define next _next
 6 typedef long long ll;
 7 struct edge{
 8     int to,next,data;
 9 }e[200010];
10 int n,m,head[100010];
11 int tot,size,maxn,a[3],color[100010]={0};
12 ll ans=0;
13 bool flag,vis[100010]={false},visp[100010]={false};
14 void dfs(int u){
15     vis[u]=true;
16     size++;
17     a[color[u]]++;
18     maxn=max(maxn,color[u]);
19     for(int i=head[u];~i;i=e[i].next)
20         if(!visp[(i+1)/2]){
21             visp[(i+1)/2]=true;
22             tot++;
23             int v=e[i].to;
24             if(!vis[v]){
25                 color[v]=(color[u]+e[i].data+3)%3;
26                 dfs(v);
27             }
28             else
29                 flag|=(color[v]!=(color[u]+e[i].data+3)%3);
30         }
31     return;
32 }
33 int main(){
34     memset(head,-1,sizeof(head));
35     scanf("%d%d",&n,&m);
36     for(int i=1,cnt=0;i<=m;i++){
37         int u,v;
38         scanf("%d%d",&u,&v);
39         e[++cnt]=(edge){v,head[u],1};
40         head[u]=cnt;
41         e[++cnt]=(edge){u,head[v],-1};
42         head[v]=cnt;
43     }
44     for(int i=1;i<=n;i++)
45         if(!vis[i]){
46             tot=size=maxn=a[0]=a[1]=a[2]=0;
47             flag=false;
48             dfs(i);
49             if(flag)
50                 ans+=(ll)size*size;
51             else if(!a[0]||!a[1]||!a[2])
52                 ans+=tot;
53             else
54                 ans+=(ll)a[0]*a[1]+(ll)a[1]*a[2]+(ll)a[2]*a[0];
55         }
56     printf("%lld\n",ans);
57     return 0;
58 }

 

posted @ 2018-08-22 21:42  乖巧的小团子QwQ  阅读(132)  评论(0编辑  收藏  举报