GMOJ 6683. 我圖呢 題解
阿新 • • 發佈:2021-07-15
簡要の題意
求二分圖 最大權 最大獨立集 的方案。
\(n\le 500\)
思路
二分圖最大權獨立集很好做,二分圖最大獨立集也很好做。
考慮 雙關鍵字排序 中第一個關鍵字無窮大於第二個關鍵字的優先順序。
所以可以令點的數量帶來的流量遠大於權值帶來的流量。
\(+\infty\) 即可。
構造方案直接按求割做。
CODE
#include<vector> #include<cstdio> #include<cstring> #include<iostream> #define reg register #define uni unsigned #define ll long long using namespace std; const int N=2010,FSIZE=1<<26; const ll Inf=1000000000,INF=0x7f7f7f7f7f7f7f7f; int n,m,h[N],a[N],last,w[N],d[N],cur[N],sum,cl[N]; ll b[N*N][3]; vector<int> T[N]; bool vis[N]; struct edge{ int x,y; }e[N*N]; char BuF[FSIZE],*InF=BuF; template<typename T>void read(T &x){ for(;47>*InF||*InF>58;++InF); for(x=0;47<*InF&&*InF<58;x=x*10+(*InF++^48)); } void add(int x,int y,ll u){ b[last][0]=a[x]; b[a[x]=last][1]=y; b[last++][2]=u; } void Add(int x,int y,ll u){ add(x,y,u); add(y,x,0); } bool bfs(){ memset(w,127,sizeof(w)); for(reg int h=0,t=w[0]=0;h<=t;h++){ cur[d[h]]=a[d[h]]; for(reg int i=a[d[h]];~i;i=b[i][0]){ if(w[b[i][1]]>w[d[h]]+1&&b[i][2]){ w[b[i][1]]=w[d[h]]+1; d[++t]=b[i][1]; } } } return(w[n+1]<0x7f7f7f7f); } ll dfs(int now,ll flow){ if(now==n+1||!flow) return(flow); ll used=0,aflow; for(reg int &i=cur[now];~i;i=b[i][0]){ if(w[b[i][1]]==w[now]+1&&b[i][2]&&(aflow=dfs(b[i][1],min(b[i][2],flow-used)))){ b[i][2]-=aflow; b[i^1][2]+=aflow; used+=aflow; if(used==flow) break; } } if(used==0) w[now]=0; return(used); } ll dinic(){ reg ll maxflow=0; for(;bfs();maxflow+=dfs(0,INF)); return(maxflow); } void find(reg int x){ vis[x]=1; for(reg int i=a[x];~i;i=b[i][0]){ if(b[i][2]&&!vis[b[i][1]]) find(b[i][1]); } } void color(reg int x,reg int c){ cl[x]=c; for(reg vector<int>::iterator i=T[x].begin();i!=T[x].end();++i) if(!~cl[*i]) color(*i,c^1); } int main(){ freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); fread(BuF,1,FSIZE,stdin); read(n);read(m); for(reg int i=0;i<n;read(h[++i])); memset(a,-1,sizeof(a)); memset(cl,-1,sizeof(cl)); for(reg int i=0;i<m;++i){ read(e[i].x);read(e[i].y); T[e[i].x].push_back(e[i].y); T[e[i].y].push_back(e[i].x); } for(reg int i=1;i<=n;++i){ sum+=h[i]; if(!~cl[i]) color(i,0); if(cl[i]) Add(i,n+1,h[i]+Inf); else Add(0,i,h[i]+Inf); } for(reg int i=0;i<m;++i){ if(cl[e[i].x]) Add(e[i].y,e[i].x,INF); else Add(e[i].x,e[i].y,INF); } ll ans=dinic(); printf("%lld %lld\n",n-ans/Inf,sum-ans%Inf); find(0); for(int i=1;i<=n;++i) putchar(vis[i]^cl[i]?'1':'0'); fclose(stdin); fclose(stdout); return(0); }