HDU-3987-Harry Potter and the Forbidden Forest(所有最小割中 割边最少的割边数)

题目

禁林是神秘的。它由从0到N-1的N个节点组成。所有食死徒都呆在编号为0的节点上。Castle的位置是node n-1。由一些道路连接的节点。哈利需要用魔法堵住一些路,他想把成本降到最低。但这还不够,哈利想知道至少有多少条路被封锁了。

输入
输入由几个测试用例组成。第一行是测试用例的数量。
对于每个测试用例,第一行包含两个整数n, m,这意味着图的节点和边的数量。每个节点编号为0到n-1。下面的m行包含关于边的信息。每一行有四个整数u v c d,前两个整数表示边的两个端点。第三是封边成本。第四个是有向(d = 0)或无向(d = 1)

  1. 2 <= n <= 1000
  2. 0 <= m <= 10000
  3. 0 <= u, v <= n-1
  4. 0 < c <= 1000000
  5. 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);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_42576687/article/details/87857433