luogu 1344

首先题意就是裸的最小割啦

然后考虑如何统计边数

这里有一个trick:

我们设定一个大于$m$的阈值,对于每条边的边权我们乘这个阈值+1后跑最小割,得到的答案除以阈值就是真正的最小割,取模阈值后就是最少割掉的边数

为什么?

我们考虑:设原来的最小割割掉的边权为$v_{1},v_{2}...v_{n}$,那么乘阈值+1后割掉的边权就是$v_{1}*lim+1,v_{2}*lim+1...v_{n}*lim+1$

也就是$lim(v_{1}+v_{2}+...+v_{n})+n$

注意到$lim$大于边权,因此我们直接跑出最小割分解就是答案

而且显然,加一不会影响最小割的正确性

贴代码:

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
using namespace std;
const ll lim=5000;
const ll inf=0x3f3f3f3f3f3f3f3fll;
struct Edge
{
    int nxt;
    int to;
    ll val;
}edge[2005];
int head[50];
int dis[50];
int cur[50];
int cnt=1;
int n,m;
void add(int l,int r,ll w)
{
    edge[cnt].nxt=head[l];
    edge[cnt].to=r;
    edge[cnt].val=w;
    head[l]=cnt++;
}
void dadd(int l,int r,ll w)
{
    add(l,r,w),add(r,l,0);
}
int ide(int x)
{
    return x&1?x+1:x-1;
}
bool bfs()
{
    memcpy(cur,head,sizeof(head));
    memset(dis,0,sizeof(dis));
    dis[1]=1;
    queue <int> M;
    M.push(1);
    while(!M.empty())
    {
        int u=M.front();
        M.pop();
        for(int i=head[u];i;i=edge[i].nxt)
        {
            int to=edge[i].to;
            if(!dis[to]&&edge[i].val)dis[to]=dis[u]+1,M.push(to);
        }
    }    
    return dis[n];
}
ll dfs(int x,ll lim)
{
    if(x==n)return lim;
    ll ret=0;
    for(int i=cur[x];i;i=edge[i].nxt)
    {
        cur[x]=i;
        int to=edge[i].to;
        if(edge[i].val&&dis[to]==dis[x]+1)
        {
            ll temp=dfs(to,min(lim,edge[i].val));
            if(temp)
            {
                ret+=temp;
                lim-=temp;
                edge[i].val-=temp;
                edge[ide(i)].val+=temp;
                if(!lim)return ret;
            }
        }
    }
    return ret;
}
ll dinic()
{
    ll ans=0;
    while(bfs())ans+=dfs(1,inf);
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        ll z;
        scanf("%d%d%lld",&x,&y,&z);
        z=z*lim+1;
        dadd(x,y,z);
    }
    ll s=dinic();
    printf("%lld %lld\n",s/lim,s%lim);
    return 0;
}

 

posted @ 2019-07-11 09:03  lleozhang  Views(140)  Comments(0Edit  收藏  举报
levels of contents