题意:Soda有一个$n$个点$m$条边的二分图, 他想要通过加边使得这张图变成一个边数最多的完全二分图. 于是他想要知道他最多能够新加多少条边. 注意重边是不允许的.
思路:二分图着色这个简单,主要是dp,还有时间限制。我觉得应该是找出所有连通分量,每个连通分量两边的点数存起来,后面统一进行DP。但是!!时间仅有1s,而且还100个例子,就是说大概要在100万的复杂度才行,可是有1万个点,当m=5000时,这就不行。
我不懂这道题如何下手才能保证一定正确且不超时,应该优化得很厉害~
贴一个我认为对的TLE代码:
1 #include <bits/stdc++.h> 2 #define LL long long 3 #define pii pair<int,int> 4 #define INF 0x7f7f7f7f 5 using namespace std; 6 const int N=10100; 7 vector<int> vect[N]; 8 int col[N]; 9 int set1, set2; 10 11 void color(int u, int c) 12 { 13 col[u]=c; 14 if(col[u]==1) set1++;//统计两边的数量 15 else set2++; 16 17 for(int i=0; i<vect[u].size(); i++) 18 { 19 int t=vect[u][i]; 20 if(!col[t]) //没色 21 color(t, 3-col[u] ); 22 } 23 } 24 25 26 bitset<N/2> dp[N]; 27 int s1[N/2],s2[N/2]; 28 int cal(int n, int m) 29 { 30 if(m==n/2*(n-n/2) ) return 0; 31 for(int i=0; i<=n; i++) vect[i].clear(), dp[i].reset(); 32 33 memset(col, 0, sizeof(col)); 34 int ans=0, k=0; 35 for(int i=1; i<=n; i++) 36 { 37 if(!col[i]) 38 { 39 set1=set2=0; 40 color(i, 1); 41 42 s1[k]=set1;//每个连通分量两边的点数 43 s2[k++]=set2; 44 } 45 } 46 47 if(k==1) return s1[0] * s2[0] - m;//连通图 48 dp[0][0]=1; 49 for(int i=0; i<k; i++)//在这进行DP,尽量使得两边的点数平衡 50 { 51 ans=0; 52 set1=s1[i]; 53 set2=s2[i]; 54 55 for(int j=n/2; j>=set1; j--) 56 if( dp[i][j-set1] ) dp[i+1][j]=1,ans=max(ans,j); 57 58 for(int j=n/2; j>=set2; j--) 59 if( dp[i][j-set2] ) dp[i+1][j]=1,ans=max(ans,j); 60 } 61 return ans*(n-ans)-m; 62 } 63 64 65 int main() 66 { 67 //freopen("input.txt", "r", stdin); 68 int n, m, t, p, q, a, b; 69 cin>>t; 70 71 while(t--) 72 { 73 scanf("%d%d",&n,&m); 74 for(int i=0; i<m; i++) 75 { 76 scanf("%d%d",&a,&b); 77 vect[a].push_back(b); 78 vect[b].push_back(a); 79 } 80 printf("%d\n",cal(n, m)); 81 } 82 return 0; 83 }
AC代码
时间: 2024-10-11 05:08:33