hdu 1569 最大流 最大點權獨立集
阿新 • • 發佈:2018-12-12
二分圖最小點權覆蓋
從x或者y集合中選取一些點,使這些點覆蓋所有的邊,並且選出來的點的權值儘可能小。
建模:
原二分圖中的邊(u,v)替換為容量為INF的有向邊(u,v),設立源點s和匯點t,將s和x集合中的點相連,容量為該點的權值;將y中的點同t相連,容量為該點的權值。在新圖上求最大流,最大流量即為最小點權覆蓋的權值和。
二分圖最大點權獨立集
在二分圖中找到權值和最大的點集,使得它們之間兩兩沒有邊。其實它是最小點權覆蓋的對偶問題。答案=總權值-最小點覆蓋集。
這題就是二分圖最大點權獨立集
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using namespace std; #define inf 0x7fffffff struct Edge{ int v,w,nxt; }g[20001]; int head[10001]; int cnt; int dir[4][2]={0,1,0,-1,1,0,-1,0}; int path[20001]; int pre[10001]; void addEdge(int u,int v,int w){ g[cnt].v = v; g[cnt].w = w; g[cnt].nxt = head[u]; head[u] = cnt; ++ cnt; } int n,m,x,y,z; int ans,flow; int dis[10001]; queue<int> q; int S,T; void init(){ memset(head,-1,sizeof(head)); memset(g,0,sizeof(g)); cnt = 0; memset(dis,-1,sizeof(dis)); while(!q.empty()) q.pop(); ans = 0; } int bfs(){ memset(dis,-1,sizeof(dis)); while(!q.empty()) q.pop(); dis[S] = 0; q.push(S); while(!q.empty()){ int u = q.front(); q.pop(); for(int i=head[u];i!=-1;i=g[i].nxt){ int v = g[i].v; if(dis[v]==-1 && g[i].w > 0){ dis[v] = dis[u] + 1; q.push(v); } } } return dis[T]!=-1; } int dfs(int u,int exp){ if(u==T) return exp; int flow=0,tmp= 0; for(int i=head[u];i!=-1;i=g[i].nxt){ int v = g[i].v; if((dis[v] == (dis[u]+1)) && (g[i].w>0)){ tmp = dfs(v,min(exp,g[i].w)); if(!tmp) continue; exp -= tmp; flow += tmp; g[i].w -= tmp; g[i^1].w += tmp; if(!exp) break; } } return flow; } int mp[55][55]; int main(){ int f,d,tmp; while(~scanf("%d%d",&n,&m)){ init(); int sum=0; S =0;T =n*m+1; for(int i=0;i<n;i++) for(int j=1;j<=m;j++) { scanf("%d",&tmp); sum+=tmp; if((i+j)%2==1) { addEdge(S,i*m+j,tmp); addEdge(i*m+j,S,0); } else { addEdge(i*m+j,T,tmp); addEdge(T,i*m+j,0); } } for(int i=0;i<n;i++) for(int j=1;j<=m;j++) { if((i+j)%2==1) { for(int k=0;k<4;k++) { int x=i+dir[k][0]; int y=j+dir[k][1]; if(x>=0&&x<n&&y>=1&&y<=m) { addEdge(i*m+j,x*m+y,inf); addEdge(x*m+y,i*m+j,0); } } } } while(bfs()){ ans += dfs(S,inf); } printf("%d\n",sum-ans); } }