禁林是神秘的。它由从0到N-1的N个节点组成。所有食死徒都呆在编号为0的节点上。Castle的位置是node n-1。由一些道路连接的节点。哈利需要用魔法堵住一些路,他想把成本降到最低。但这还不够,哈利想知道至少有多少条路被封锁了。
输入
输入由几个测试用例组成。第一行是测试用例的数量。
对于每个测试用例,第一行包含两个整数n, m,这意味着图的节点和边的数量。每个节点编号为0到n-1。下面的m行包含关于边的信息。每一行有四个整数u v c d,前两个整数表示边的两个端点。第三是封边成本。第四个是有向(d = 0)或无向(d = 1)
- 2 <= n <= 1000
- 0 <= m <= 10000
- 0 <= u, v <= n-1
- 0 < c <= 1000000
- 0 <= d <= 1
输出
对于每个测试用例:
输出案例编号和至少阻塞了多少条道路的答案。
最小割中 割边数目最小的割边数。有两种方法:
一。割边一定是满流。满流不一定为该次所求的割边 但是很可能是割边的备选人员 。换句话说可能是其他最小割情况的割边。但也可能什么都不是。
将满流的边容量设为 1 其余的边容量为INF 重新跑一个最大流也就是最小割
得到的最小割就是割边最小的数。
二。若边的总数为M。则每条边的容量设为val*(M+1)+1;
最小割=maxflow/(M+1)。割边最小数=maxflow%(M+1)。
即使M条边都被割完的话 那个多余的零头才为 M。
不可能 存在本来不是最小割因为这一点儿零头比别人大 成为了答案的情况。
这种方法要求 val>=1;
//---------方法一 dinic
#include <queue>
#include <cstring>
#include <cstdio>
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
const int N=1000+5;
const int M=100000+5;
const int INF=0x3f3f3f3f;
struct Edge{int to,len,nex;}edge[M*4];
int head[N],d[N];
int tot,s,t,n,m;
void add(int from,int to,int len)
{
edge[++tot]=(Edge){to,len,head[from]};head[from]=tot;
edge[++tot]=(Edge){from,0,head[to]};head[to]=tot;
}
queue<int>q;
bool bfs()
{
while(!q.empty())
q.pop();
m(d,0);
q.push(s);
d[s]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to,l=edge[i].len;
if(!d[y]&&l)
{
d[y]=d[x]+1;
q.push(y);
if(y==t)
return 1;
}
}
}
return 0;
}
int dinic(int x,int flow)
{
if(x==t)
return flow;
int res=flow,k;
for(int i=head[x];i&&res;i=edge[i].nex)
{
int y=edge[i].to,l=edge[i].len;
if(l&&d[y]==d[x]+1)
{
k=dinic(y,min(res,l));
if(!k)
{
d[y]=0;
continue;
}
edge[i].len-=k;
edge[i^1].len+=k;
res-=k;
}
}
return flow-res;
}
int main()
{
int T;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++)
{
m(head,0);
tot=1;
int n,m;
scanf("%d%d",&n,&m);
s=1,t=n;
while(m--)
{
int x,y,v,flag;
scanf("%d%d%d%d",&x,&y,&v,&flag);
x++,y++;
add(x,y,v);
if(flag)
add(y,x,v);
}
while(bfs())
dinic(s,INF);
for(int i=2;i<=tot;i+=2)
{
edge[i].len=(edge[i].len)?INF:1;
edge[i^1].len=0;
}
int ans=0;
while(bfs())
ans+=dinic(s,INF);
printf("Case %d: %d\n",cas,ans);
}
}
//---------方法二 sap( 模板是网上找的 不想去看了 ) 这个用dinic过不了 我也不知道为什么!
#include <queue>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll N=1000+5;
const ll M=100000+5;
const ll INF=0x3f3f3f3f;
struct Node
{
ll to,next,cap;
}edge[M*4];
ll tot;
ll head[N];
ll gap[N],dis[N],pre[N],cur[N];
void add(ll u,ll v,ll w,ll rw=0)
{
edge[tot].to=v;edge[tot].cap=w;edge[tot].next=head[u];head[u]=tot++;
edge[tot].to=u;edge[tot].cap=rw;edge[tot].next=head[v];head[v]=tot++;
}
ll sap(ll s,ll t,ll nodenum)
{
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
memcpy(cur,head,sizeof(head));
ll u=pre[s]=s,maxflow=0,aug=-1;
gap[0]=nodenum;
while(dis[s]<nodenum)
{
loop:
for(ll &i=cur[u];i!=-1;i=edge[i].next)
{
ll v=edge[i].to;
if(edge[i].cap&&dis[u]==dis[v]+1)
{
if(aug==-1||aug>edge[i].cap)
aug=edge[i].cap;
pre[v]=u;
u=v;
if(v==t)
{
maxflow+=aug;
for(u=pre[u];v!=s;v=u,u=pre[u])
{
edge[cur[u]].cap-=aug;
edge[cur[u]^1].cap+=aug;
}
aug=-1;
}
goto loop;
}
}
ll mindis=nodenum;
for(ll i=head[u];i!=-1;i=edge[i].next)
{
ll v=edge[i].to;
if(edge[i].cap&&mindis>dis[v])
{
cur[u]=i;
mindis=dis[v];
}
}
if((--gap[dis[u]])==0)break;
gap[dis[u]=mindis+1]++;
u=pre[u];
}
return maxflow;
}
int main()
{
ll T,n,m;
scanf("%lld",&T);
for(ll cas=1;cas<=T;cas++)
{
tot=0;
memset(head,-1,sizeof(head));
ll n,m;
scanf("%lld%lld",&n,&m);
while(m--)
{
ll x,y,v,flag;
scanf("%lld%lld%lld%lld",&x,&y,&v,&flag);
x++,y++;
add(x,y,(ll)(v*M+1));
if(flag)
add(y,x,(ll)(v*M+1));
}
printf("Case %lld: %lld\n",cas,sap(1,n,n)%M);
}
}