//Destroying The Graph poj 2125
//目前想法是拆点加最小点权覆盖
//这道题的特殊点在于他还要寻找最小点权覆盖选择的是:1-n取s能遍历到的点,n+1-2*n取s遍历不到的点
//
那个求割点的重点在于一定要用visit,别用vis,重名了
//题意就是 有一个图, 两种操作,一种是删除某点的所有出边,一种是删除某点的所有入边,各个点的不同操作分别有一个花费,
//现在我们想把这个图的边都删除掉,需要的最小花费是多少
//还要输出选择的点
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<vector>
#include<queue>
#define maxn 1050
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f
using namespace std;
int n,m;
bool visit[maxn*2];
int wz[maxn],wf[maxn];
int s,dest;
int res[maxn];
bool index[maxn];
///注意有向边还是无向边
struct Dinic
{
int edgeNum,source,sink;
bool vis[maxn];
int d[maxn];
int cur[maxn];
int mark[maxn];
struct edge
{
int from,to,cap,flow;
};
vector<edge> edges;
vector<int> mapt[maxn];
void addEdge(int from,int to,int cap){
//pf("%d %d %d\n",from,to,cap);
edges.push_back((edge){from,to,cap,0});
edges.push_back((edge){to,from,0,0});
edgeNum = edges.size();
mapt[from].push_back(edgeNum-2);
mapt[to].push_back(edgeNum-1);
}
bool bfs()
{
memset(vis,0,sizeof vis);
queue<int> q;
q.push(source);
d[source] =0; vis[source] =1;
while(!q.empty()){
int x = q.front(); q.pop();
for(int i=0;i<mapt[x].size();i++){
edge& e = edges[mapt[x][i]];
if(!vis[e.to]&&e.cap>e.flow){
vis[e.to] = 1;
d[e.to] = d[x] +1;
q.push(e.to);
}
}
}
return vis[sink];
}
int dfs(int x,int a)
{
if(x==sink||a==0) return a;
int flow=0,f;
for(int& i=cur[x];i<mapt[x].size();i++){
edge& e = edges[mapt[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
e.flow += f;
edges[mapt[x][i]^1].flow -= f;
flow += f;
a -= f;
if(a==0) break;
}
}
return flow;
}
int maxFlow(int source,int sink){
this->sink = sink; this->source = source;
int flow = 0;
while(bfs())
{
memset(cur,0,sizeof cur);
flow += dfs(source,INF);
}
return flow;
}
void dfsans(int x)
{
visit[x]=true;
for(int i=0;i<mapt[x].size();i++)
{
edge& e = edges[mapt[x][i]];
if(e.cap>e.flow)
{
if(!visit[e.to])
dfsans(e.to);
}
}
}
};
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
Dinic dinic;
s=0;
dest=n+n+1;
for(int i=1;i<=n;i++)
scanf("%d",&wz[i]);
for(int i=1;i<=n;i++)
scanf("%d",&wf[i]);
int tempa,tempb;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&tempa,&tempb);
dinic.addEdge(tempa,tempb+n,inf);
}
for(int i=1;i<=n;i++)
{
dinic.addEdge(s,i,wf[i]);
}
for(int i=1;i<=n;i++)
{
dinic.addEdge(n+i,dest,wz[i]);
}
cout<<dinic.maxFlow(s,dest)<<endl;
memset(visit,false,sizeof(visit));
dinic.dfsans(s);
int tot=0;
for(int i=1;i<=2*n;i++)
{
// cout<<i<<" "<<visit[i]<<endl;
if((i<=n)&&!visit[i])
{
tot++;
res[tot]=i;
index[tot]=false;
}
else if((i>n)&&visit[i])
{
tot++;
res[tot]=i-n;
index[tot]=true;
}
}
cout<<tot<<endl;
for(int i=1;i<=tot;i++)
{
cout<<res[i];
if(index[i])
cout<<" +\n";
else
cout<<" -\n";
}
}
}
POJ 2125 网络流拆点最小点权覆盖
最新推荐文章于 2016-08-05 11:11:14 发布