cf D George and Interesting Graph
题意:给你一个有趣图的定义:在这个图中有一个根,根与每个点都有边和回边,除了根之外,其他的点的出度和入度都为2,然后给你一个图让你经过几步操作可以使此图变为有趣图,操作为:删边或者加边。
思路:枚举根,然后删除与根有关的边,重新建图,用二分图求最大匹配,可以用匈牙利算法,加的边数:满足题中有关根的加边数+(点数-匹配数),删掉的边数:边数-满足题中有关根的使用的边数-匹配时使用的边数。
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <algorithm> 5 using namespace std; 6 const int inf=1<<29; 7 8 int g[600][600]; 9 int n,m; 10 bool chk[600]; 11 int match[600]; 12 vector<int>x[600]; 13 14 int dfs(int p) 15 { 16 for(int i=0; i<(int)x[p].size(); i++) 17 { 18 int v=x[p][i]; 19 if(!chk[v]) 20 { 21 chk[v]=true; 22 int t=match[v]; 23 match[v]=p; 24 if(t==-1||dfs(t)) 25 { 26 return 1; 27 } 28 match[v]=t; 29 } 30 } 31 return 0; 32 } 33 34 int Pro(int c) 35 { 36 memset(match,-1,sizeof(match)); 37 int res=0; 38 for(int i=1; i<=n; i++) 39 { 40 if(i==c) continue; 41 memset(chk,false,sizeof(chk)); 42 res+=dfs(i); 43 } 44 return res; 45 } 46 47 int main() 48 { 49 while(scanf("%d%d",&n,&m)!=EOF) 50 { 51 vector<int>gg[600]; 52 for(int i=1; i<=m; i++) 53 { 54 int u,v; 55 scanf("%d%d",&u,&v); 56 gg[u].push_back(v); 57 g[u][v]=1; 58 } 59 int ans=inf; 60 for(int i=1; i<=n; i++) 61 { 62 int t1=n-gg[i].size(); 63 for(int j=1; j<=n; j++) 64 { 65 if(!g[j][i]) t1++; 66 } 67 if(g[i][i]==0) t1--; 68 for(int j=1; j<=n; j++) 69 { 70 x[j].clear(); 71 } 72 int cnt=0; 73 for(int j=1; j<=n; j++) 74 { 75 if(j==i) continue; 76 for(int k=0; k<(int)gg[j].size(); k++) 77 { 78 int v=gg[j][k]; 79 if(v==i)continue; 80 cnt++; 81 x[j].push_back(v); 82 } 83 } 84 ans=min(ans,t1+cnt+n-1-2*Pro(i)); 85 } 86 printf("%d\n",ans); 87 } 88 return 0; 89 }