题目内容:
题目分析:有选A则必须选B这样的限制条件,可以发现这是最大权闭合子图模型,考虑环的情况,可以推测需要拓扑判环。
代码:
#include<bits/stdc++.h> using namespace std; struct edge{ int from,to,flow; }e[520000]; const int maxn = 35,inf = 1000000000; int n,m,num,tmp = 1500; int sc[maxn][maxn]; vector <int> at[maxn][maxn]; vector <int> g[maxn*maxn+1000]; vector <int> ng[maxn*maxn+1000]; void AddEdge(int from,int to,int w){ e[num++] = (edge){from,to,w}; g[from].push_back(num-1); e[num++] = (edge){to,from,0}; g[to].push_back(num-1); } int tp[maxn*maxn+1000],in[maxn*maxn+1000]; void topu(){ for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ if(j < m)ng[(i-1)*m+j+1].push_back((i-1)*m+j),in[(i-1)*m+j]++; for(int k=0;k<at[i][j].size();k++){ int now = at[i][j][k]; ng[(i-1)*m+j].push_back(now); in[now] ++; } } queue <int> q; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)if(!in[(i-1)*m+j])q.push((i-1)*m+j); while(!q.empty()){ int k = q.front();q.pop(); tp[k] = 1; for(int i=0;i<ng[k].size();i++){ in[ng[k][i]]--; if(!in[ng[k][i]])q.push(ng[k][i]); } } for(int i=1;i<=n*m;i++)ng[i].clear(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ if(j < m)ng[(i-1)*m+j+1].push_back((i-1)*m+j); for(int k=0;k<at[i][j].size();k++){ int now = at[i][j][k],now2 = (i-1)*m+j; ng[now2].push_back(now); } } for(int i=1;i<=n*m;i++) if(tp[i] == 0) q.push(i); while(!q.empty()){ int k = q.front();q.pop(); for(int i=0;i<ng[k].size();i++){ if(tp[ng[k][i]]==0)continue; tp[ng[k][i]]=0;q.push(ng[k][i]); } } } void build_graph(){ topu(); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(tp[(i-1)*m+j]==0)continue; if(sc[i][j] > 0)AddEdge(0,(i-1)*m+j,sc[i][j]); else AddEdge((i-1)*m+j,tmp,-sc[i][j]); for(int k=0;k<at[i][j].size();k++){ int now = at[i][j][k]; if(tp[now]==0)continue; AddEdge(now,(i-1)*m+j,inf); } if(j < m && tp[(i-1)*m+j+1])AddEdge((i-1)*m+j,(i-1)*m+j+1,inf); } } } void read(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ for(int j=1,x;j<=m;j++){ scanf("%d%d",&sc[i][j],&x); for(int k=1,p1,q1;k<=x;k++) { scanf("%d%d",&p1,&q1);p1++;q1++; at[i][j].push_back((p1-1)*m+q1); } } } build_graph(); } int dis[maxn*maxn+1000],cur[maxn*maxn+1000]; int BFS(){ queue <int> q; memset(dis,-1,sizeof(dis)); q.push(0); dis[0] = 0; while(!q.empty()){ int k = q.front();q.pop(); for(int i=0;i<g[k].size();i++){ edge nxt = e[g[k][i]]; if(nxt.flow > 0 && (dis[nxt.to]==-1)){ dis[nxt.to] = dis[k]+1; q.push(nxt.to); } } } return dis[tmp]; } int dfs(int x,int a){ if(x == tmp || a == 0) return a; int flow = 0,f; for(int &i=cur[x];i<g[x].size();i++){ edge &eg = e[g[x][i]]; if(dis[eg.to] > dis[x] && ((f = dfs(eg.to,min(eg.flow,a)))>0)){ eg.flow -= f; e[g[x][i]^1].flow += f; a -= f; flow += f; if(a == 0) break; } } return flow; } void work(){ int flow; while(BFS()!=-1){ memset(cur,0,sizeof(cur)); flow = dfs(0,inf); } int ans = 0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(dis[(i-1)*m+j]!=-1) ans += sc[i][j]; } } printf("%d",ans); } int main(){ read(); work(); return 0; }