链接:https://cn.vjudge.net/problem/HDU-3987
题意:t组样例,第一行给出n、m。(n个点,m条边。)源点为0,汇点为n-1。接下来m行,每行有u、v、w、d,分别表示边的两端点,容量。d为1代表双向边,为0代表单向边。求最小割的边数。
思路:最小割就是最大流。而且最小割的边都是满流的边,我们给每条边乘上一个很大的数(mod),算最小割。然后,对mod取模得到的就是最小割的边数。有的Dinic算法。
109ms:一次dfs找一条增广路
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3+10;
const int M = 4e5+10;
const ll mod=1e6+3;
const ll inf =1e18;
struct node
{
int to,next;
ll ca;
}g[M];
int n,m,cnt,head[N],cur[N],deep[N];
void Init()
{
cnt=0;
for(int i=0;i<n;i++)
head[i]=-1;
return ;
}
void add(int u,int v,ll w)
{
g[cnt].to=v;
g[cnt].ca=w;
g[cnt].next=head[u];
head[u]=cnt++;
return ;
}
bool bfs(int s,int t)
{
queue<int> q;
int u,v;
for(int i=s;i<=t;i++)
deep[i]=0;
deep[s]=1;
q.push(s);
while(!q.empty())
{
u=q.front();
q.pop();
if(u==t) return 1;
for(int i=head[u];i!=-1;i=g[i].next)
{
v=g[i].to;
if(g[i].ca>0&&!deep[v])
{
deep[v]=deep[u]+1;
q.push(v);
}
}
}
return deep[t]!=0;
}
ll dfs(int u,ll flow,int t)
{
if(u==t||!flow) return flow;
int v;
ll nowflow;
for(int& i=cur[u];i!=-1;i=g[i].next)
{
v=g[i].to;
if(g[i].ca>0&&deep[v]==deep[u]+1)
{
nowflow=dfs(v,min(flow,g[i].ca),t);
if(nowflow>0)
{
g[i].ca-=nowflow;
g[i^1].ca+=nowflow;
return nowflow;
}
}
}
return 0;
}
ll Dinic(int s,int t)
{
ll maxflow=0,flow;
while(bfs(s,t))
{
for(int i=s;i<=t;i++)
cur[i]=head[i];
while(flow=dfs(s,inf,t))
{
maxflow+=flow;
}
}
return maxflow%mod;
}
int main(void)
{
int t,tt,u,v,op;
ll w;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
Init();
for(int i=1;i<=m;i++)
{
scanf("%d%d%lld%d",&u,&v,&w,&op);
add(u,v,w*mod+1);
add(v,u,0);
if(op)
{
add(v,u,w*mod+1);
add(u,v,0);
}
}
printf("Case %d: %lld\n",++tt,Dinic(0,n-1));
}
return 0;
}
93ms:一次dfs找多条增广路
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3+10;
const int M = 4e5+10;
const ll mod=1e6+3;
const ll inf =1e18;
struct node
{
int to,next;
ll ca;
}g[M];
int n,m,cnt,head[N],cur[N],deep[N];
void Init()
{
cnt=0;
for(int i=0;i<n;i++)
head[i]=-1;
return ;
}
void add(int u,int v,ll w)
{
g[cnt].to=v;
g[cnt].ca=w;
g[cnt].next=head[u];
head[u]=cnt++;
return ;
}
bool bfs(int s,int t)
{
queue<int> q;
int u,v;
for(int i=s;i<=t;i++)
deep[i]=0;
deep[s]=1;
q.push(s);
while(!q.empty())
{
u=q.front();
q.pop();
if(u==t) return 1;
for(int i=head[u];i!=-1;i=g[i].next)
{
v=g[i].to;
if(g[i].ca>0&&!deep[v])
{
deep[v]=deep[u]+1;
q.push(v);
}
}
}
return deep[t]!=0;
}
ll dfs(int u,ll flow,int t)//dfs一次找多条增广路
{
if(u==t||!flow) return flow;
int v;
ll fflow=0;//从u点流出去的总容量
ll nowflow;//从当前边流出去的流量
for(int& i=cur[u];i!=-1;i=g[i].next)
{
v=g[i].to;
if(g[i].ca>0&&deep[v]==deep[u]+1)
{
nowflow=dfs(v,min(flow,g[i].ca),t);
if(nowflow>0)
{
flow-=nowflow;
g[i].ca-=nowflow;
g[i^1].ca+=nowflow;
fflow+=nowflow;
if(!flow) break;//如果流量用完break
}
}
}
if(!fflow) deep[u]=0;//如果流量用完,下次就不用再从u往下找增广路
return fflow; //返回从u点流出去的总容量
}
ll Dinic(int s,int t)
{
ll maxflow=0,flow;
while(bfs(s,t))
{
for(int i=s;i<=t;i++)
cur[i]=head[i];
while(flow=dfs(s,inf,t))
{
maxflow+=flow;
}
}
return maxflow%mod;
}
int main(void)
{
int t,tt,u,v,op;
ll w;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
Init();
for(int i=1;i<=m;i++)
{
scanf("%d%d%lld%d",&u,&v,&w,&op);
add(u,v,w*mod+1);
add(v,u,0);
if(op)
{
add(v,u,w*mod+1);
add(u,v,0);
}
}
printf("Case %d: %lld\n",++tt,Dinic(0,n-1));
}
return 0;
}