Bipartite Graph
(HDU - 5313 )
若干个二分图两侧的点数是定值,现在就是要选择翻转一些二分图,再拼起来,最后使得两边的点数尽量接近,这样可以达到最大。
考虑背包DP,dp[i]表示i这个值是否凑的出来,有:
if(dp[i]) dp[i+w[now]]=1
那么就很套路地使用Bitset优化,每次只要或一下左移后的结果就行了。
CODE:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <bitset> #include <vector> using namespace std; const int maxn=1e4+10; const int maxm=1e5+10; struct point { int to; int nxt; }edge[maxm*2]; struct nod { int a,b; nod(int a,int b):a(a),b(b) {}; }; int n,m,T,na,nb,tot; vector<nod> ans; int vis[maxn],head[maxn]; inline void add(int u,int v) { tot++; edge[tot].nxt=head[u]; edge[tot].to=v; head[u]=tot; } inline void dfs(int x,int ff) { if(ff) na++; else nb++; vis[x]=1; for(int i=head[x];i;i=edge[i].nxt) { int v=edge[i].to; if(vis[v]) continue; dfs(v,ff^1); } } int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); tot=0; memset(vis,0,sizeof(vis)); memset(head,0,sizeof(head)); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v),add(v,u); } ans.clear(); for(int i=1;i<=n;i++) if(!vis[i]) { na=nb=0; dfs(i,0); ans.push_back(nod(na,nb)); } bitset<maxn> aa; aa.set(0); int mm=ans.size(); for(int i=0;i<mm;i++) aa=(aa<<ans[i].a)|(aa<<ans[i].b); int Max=0; for(int i=1;i<=n;i++) if(aa[i]) Max=max(Max,i*(n-i)-m); printf("%d\n",Max); } return 0; }
连通数
很明显的Floyd传递闭包,但是会TLE,开n个Bitset f[i] 表示i可以到达的点集,每次传递的时候只要或一下就行了,注意循环的顺序。
每次把所有的点都要更新一遍,改成三重循环看一下就知道了。
CODE:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <bitset> using namespace std; const int maxn=2003; bitset<maxn> f[maxn]; int n; char ss[maxn]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",ss+1); for(int j=1;j<=n;j++) if(ss[j]-'0' || i==j) f[i][j]=1; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(f[j][i]) f[j]|=f[i]; int ans=0; for(int i=1;i<=n;i++) ans+=f[i].count(); printf("%d",ans); return 0; }