网络流<平面图&&对偶图>

开始学习,冲
BZOJ 狼抓兔子
懵逼一整天,终于搞明白平面图怎么转对偶图了
如果直接暴力跑最小割(最大流) 那么肯定TLE
根据平面图的性质 我们把它转化为对偶图跑最短路也就是原图的最小割

对偶图 洛谷博客
翻了一天了 对偶图的博客,终于找到了讲怎么转化的了
我们把每个面(小三角形) 看成点, 它与外界的公共边就是对偶图要阻挡的边,边权相同

 #include<bits/stdc++.h>
#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll int
//#define int long long
#define inf 0x3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
 using namespace std;
 ll gcd(ll a,ll b){
    
    if(a<0)a=-a;if(b<0)b=-b;return b==0?a:gcd(b,a%b);}
template<typename T>void read(T &res){
    
    bool flag=false;char ch;while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
for(res=ch-48;isdigit(ch=getchar());res=(res<<1)+(res<<3)+ch - 48);flag&&(res=-res);}
ll lcm(ll a,ll b){
    
    return a*b/gcd(a,b);}
ll qp(ll a,ll b,ll mod){
    
    ll ans=1;if(b==0){
    
    return ans%mod;}while(b){
    
    if(b%2==1){
    
    b--;ans=ans*a%mod;}a=a*a%mod;b=b/2;}return ans%mod;}//快速幂%
ll qpn(ll a,ll b, ll p){
    
    ll ans = 1;a%=p;while(b){
    
    if(b&1){
    
    ans = (ans*a)%p;--b;}a =(a*a)%p;b >>= 1;}return ans%p;}//逆元   (分子*qp(分母,mod-2,mod))%mod;

ll fact_pow(ll n,ll p){
    
    ll res=0;while(n){
    
    n/=p;res+=n;}return res;}
ll mult(ll a,ll b,ll p)
{
    
    
    a%=p;
    b%=p;
    ll r=0,v=a;
    while(b)
    {
    
    
        if(b&1)
        {
    
    
            r=(r+v)%p;

               r=(r+p)%p;
        }
        v<<=1;
        v=(v+p)%p;
        b>>=1;
    }
    return r%p;
}
ll pow_mod(ll x,ll n,ll mod)
{
    
    
    ll res=1;
    while(n)
    {
    
    
        if(n&1)
        res=mult(res,x,mod);
        x=mult(x,x,mod);
        n>>=1;
    }
    return res;
}
ll quick_pow(ll a,ll b,ll p){
    
    ll r=1,v=a%p;while(b){
    
    if(b&1)r=mult(r,v,p);v=mult(v,v,p);b>>=1;}return r;}
bool CH(ll a,ll n,ll x,ll t)
{
    
    ll r=quick_pow(a,x,n);ll z=r;for(ll i=1;i<=t;i++){
    
    r=mult(r,r,n);if(r==1&&z!=1&&z!=n-1)return true;z=r;}return r!=1;}
bool Miller_Rabin(ll n)
{
    
    if(n<2)return false;if(n==2)return true;if(!(n&1))return false;ll x=n-1,t=0;while(!(x&1)){
    
    x>>=1;t++;}
srand(time(NULL));ll o=8;for(ll i=0;i<o;i++){
    
    ll a=rand()%(n-1)+1;if(CH(a,n,x,t))return false;}return true;}
ll exgcd(ll a,ll b,ll &x,ll &y){
    
    
    if (!b){
    
    
        x=1,y=0;
        return a;
    }
    ll ans=exgcd(b,a%b,y,x);
    y-=(a/b)*x;
    return ans;
}
ll INV(ll a,ll b){
    
    ll x,y;return exgcd(a,b,x,y),(x%b+b)%b;}
ll crt(ll x,ll p,ll mod){
    
    return INV(p/mod,mod)*(p/mod)*x;}
ll FAC(ll x,ll a,ll b)
{
    
    if(!x)return 1;ll ans=1;for(ll i=1;i<=b;i++)if(i%a)ans*=i,ans%=b;
ans=pow_mod(ans,x/b,b);for(ll i=1;i<=x%b;i++)if(i%a)ans*=i,ans%=b;return ans*FAC(x/a,a,b)%b;}
ll C(ll n,ll m,ll a,ll b)
{
    
    ll N=FAC(n,a,b),M=FAC(m,a,b),Z=FAC(n-m,a,b),sum=0,i;for(i=n;i;i=i/a)sum+=i/a;
for(i=m;i;i=i/a)sum-=i/a;for(i=n-m;i;i=i/a)sum-=i/a;return N*pow_mod(a,sum,b)%b*INV(M,b)%b*INV(Z,b)%b;}
ll exlucas(ll n,ll m,ll p)
{
    
    ll t=p,ans=0,i;for(i=2;i*i<=p;i++){
    
    ll k=1;while(t%i==0){
    
    k*=i,t/=i;}
ans+=crt(C(n,m,i,k),p,k),ans%=p;}if(t>1)ans+=crt(C(n,m,t,t),p,t),ans%=p;return ans % p;}
ll H(ll x,ll p)  //错排
{
    
    
       ll ans=0;
    if(x==0)return 1;
    x=x%(2*p);
    if(x==0)x=2*p;
    for(int i=2;i<=x;++i)
    ans=(ans*i+(i%2==0?1:-1))%p;
    return (ans+p)%p;
}


const int manx=2222222;
const int mamx=6666666;
ll head[manx],d[manx];
bool vis[manx];
ll n,m,k=0,s,e,kk,ans;
struct node{
    
    
    ll v,next,w;
}a[mamx];
void add(ll u,ll v,ll w)
{
    
    
    a[++k].next=head[u];
    a[k].w=w;
    a[k].v=v;
    head[u]=k;
}
void dij()
{
    
    
    memset(d,inf,sizeof(d));
    memset(vis,0,sizeof(vis));
    d[s]=0;
    priority_queue<pair<ll,ll> >q;
    q.push(mp(0,s));
    while(q.size()){
    
    
        ll u=q.top().se;
        q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u];i;i=a[i].next){
    
    
            ll v=a[i].v,w=a[i].w;
           if(d[v]>d[u]+w){
    
    
          //printf("qwq %lld\n",d[v]);      //松弛操作,更新距离
            d[v]=d[u]+w;
           // printf("sad %lld %lld %lld %lld\n",d[u],u,res,d[v]);
            q.push(mp(-d[v],v)); //把更新的距离和点入队,这里距离取负变成小根堆
            }

        }
    }
}
ll pos[2100][1100];
signed main(){
    
    
ll zyx;
read(n);
read(m);
ll tot=0;
for(int i=1;i<=n*2-2;i++){
    
    
  for(int j=1;j<m;j++){
    
    
  //平面标号
  pos[i][j]=++tot;
  }

}
s=0;
zyx=tot+1;
//=++tot; //起点
//zyx=s+1;//终点
for(int i=1,id=1;i<=n;i++,id=id+2){
    
    
for(int j=1;j<=m-1;j++){
    
    
ll u=s;
ll v=zyx;
ll w;
read(w);
if(i!=1){
    
    
    v=pos[id-1][j];
}
if(i!=n){
    
    
  u=pos[id][j];
}
 add(u,v,w);
 add(v,u,w);
}

}

 for(int i=1,id=1;i<=n-1;i++,id=id+2){
    
    
for(int j=1;j<=m;j++){
    
    
ll u=s;
ll v=zyx;
ll w;
read(w);
if(j!=1){
    
    
    u=pos[id][j-1];
}
if(j!=m){
    
    
  v=pos[id+1][j];
}
  add(u,v,w);
 add(v,u,w);
}

}
   for(int i=1,id=1;i<=n-1;i++,id=id+2){
    
    
for(int j=1;j<=m-1;j++){
    
    
ll u=pos[id][j];
ll v=pos[id+1][j];
ll w;
read(w);
  add(u,v,w);
 add(v,u,w);

}

}
dij();
printf("%lld\n",d[zyx]);

return 0;
}

牛客暑假2020多校第二场I题 对偶图Interval
首先对偶图的应用特点是只能用于网格
题目的大概意思就是人在(1,n) 每次可以上下 左右走 现在要颁布m条禁令, 分为两种 L,R L禁令 那么对于禁令对应的位置,你是不可以移动到他的右边一个单位,也不可以从别的地方移动到禁令的位置 R禁令就是不能上下移动 ,现在问使得人不能到达L=R 的位置 最小的禁令花费是多少,如果不能阻挡,输出-1
显然如果人能够从(1,n)走到 (n,1) 一定是无解的
也就是说如果从起点到 (n,1) 是联通的则一定无解,最小的代价就是鸽边以后使得不联通的最小代价,那么我们只需要把禁令边鸽掉一些,正常边 边容建立inf (不可鸽) 跑一次Dinic 就OK 显然会TLE 那么就联想到平面图转化成对偶图跑最短路吧 对于L =R以下的区域其实我们可以不考虑
在这里插入图片描述
然后就是毒瘤的建立对偶图的过程

 #include<bits/stdc++.h>
#include<stdlib.h>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
#include<time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll long long
#define int long long
#define inf 0x3f3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define IOS ios::sync_with_stdio(false);cin.tie(0)
 using namespace std;
 ll gcd(ll a,ll b){
    
    if(a<0)a=-a;if(b<0)b=-b;return b==0?a:gcd(b,a%b);}
template<typename T>void read(T &res){
    
    bool flag=false;char ch;while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
for(res=ch-48;isdigit(ch=getchar());res=(res<<1)+(res<<3)+ch - 48);flag&&(res=-res);}
ll lcm(ll a,ll b){
    
    return a*b/gcd(a,b);}
ll qp(ll a,ll b,ll mod){
    
    ll ans=1;if(b==0){
    
    return ans%mod;}while(b){
    
    if(b%2==1){
    
    b--;ans=ans*a%mod;}a=a*a%mod;b=b/2;}return ans%mod;}//快速幂%
ll qpn(ll a,ll b, ll p){
    
    ll ans = 1;a%=p;while(b){
    
    if(b&1){
    
    ans = (ans*a)%p;--b;}a =(a*a)%p;b >>= 1;}return ans%p;}//逆元   (分子*qp(分母,mod-2,mod))%mod;

ll fact_pow(ll n,ll p){
    
    ll res=0;while(n){
    
    n/=p;res+=n;}return res;}
ll mult(ll a,ll b,ll p)
{
    
    
    a%=p;
    b%=p;
    ll r=0,v=a;
    while(b)
    {
    
    
        if(b&1)
        {
    
    
            r=(r+v)%p;

               r=(r+p)%p;
        }
        v<<=1;
        v=(v+p)%p;
        b>>=1;
    }
    return r%p;
}
ll pow_mod(ll x,ll n,ll mod)
{
    
    
    ll res=1;
    while(n)
    {
    
    
        if(n&1)
        res=mult(res,x,mod);
        x=mult(x,x,mod);
        n>>=1;
    }
    return res;
}
ll quick_pow(ll a,ll b,ll p){
    
    ll r=1,v=a%p;while(b){
    
    if(b&1)r=mult(r,v,p);v=mult(v,v,p);b>>=1;}return r;}
bool CH(ll a,ll n,ll x,ll t)
{
    
    ll r=quick_pow(a,x,n);ll z=r;for(ll i=1;i<=t;i++){
    
    r=mult(r,r,n);if(r==1&&z!=1&&z!=n-1)return true;z=r;}return r!=1;}
bool Miller_Rabin(ll n)
{
    
    if(n<2)return false;if(n==2)return true;if(!(n&1))return false;ll x=n-1,t=0;while(!(x&1)){
    
    x>>=1;t++;}
srand(time(NULL));ll o=8;for(ll i=0;i<o;i++){
    
    ll a=rand()%(n-1)+1;if(CH(a,n,x,t))return false;}return true;}
ll exgcd(ll a,ll b,ll &x,ll &y){
    
    
    if (!b){
    
    
        x=1,y=0;
        return a;
    }
    ll ans=exgcd(b,a%b,y,x);
    y-=(a/b)*x;
    return ans;
}
ll INV(ll a,ll b){
    
    ll x,y;return exgcd(a,b,x,y),(x%b+b)%b;}
ll crt(ll x,ll p,ll mod){
    
    return INV(p/mod,mod)*(p/mod)*x;}
ll FAC(ll x,ll a,ll b)
{
    
    if(!x)return 1;ll ans=1;for(ll i=1;i<=b;i++)if(i%a)ans*=i,ans%=b;
ans=pow_mod(ans,x/b,b);for(ll i=1;i<=x%b;i++)if(i%a)ans*=i,ans%=b;return ans*FAC(x/a,a,b)%b;}
ll C(ll n,ll m,ll a,ll b)
{
    
    ll N=FAC(n,a,b),M=FAC(m,a,b),Z=FAC(n-m,a,b),sum=0,i;for(i=n;i;i=i/a)sum+=i/a;
for(i=m;i;i=i/a)sum-=i/a;for(i=n-m;i;i=i/a)sum-=i/a;return N*pow_mod(a,sum,b)%b*INV(M,b)%b*INV(Z,b)%b;}
ll exlucas(ll n,ll m,ll p)
{
    
    ll t=p,ans=0,i;for(i=2;i*i<=p;i++){
    
    ll k=1;while(t%i==0){
    
    k*=i,t/=i;}
ans+=crt(C(n,m,i,k),p,k),ans%=p;}if(t>1)ans+=crt(C(n,m,t,t),p,t),ans%=p;return ans % p;}
ll H(ll x,ll p)  //错排
{
    
    
       ll ans=0;
    if(x==0)return 1;
    x=x%(2*p);
    if(x==0)x=2*p;
    for(int i=2;i<=x;++i)
    ans=(ans*i+(i%2==0?1:-1))%p;
    return (ans+p)%p;
}


const int manx=3*1e5+500;
const int mamx=2*1e6+700;
ll head[manx],d[manx];
bool vis[manx];
ll n,m,k=0,s,e,kk,ans;
struct node{
    
    
    ll v,next,w;
}a[mamx];
void add(ll u,ll v,ll w)
{
    
    
    a[++k].next=head[u];
    a[k].w=w;
    a[k].v=v;
    head[u]=k;
}
void dij()
{
    
    
    memset(d,inf,sizeof(d));
    memset(vis,0,sizeof(vis));
    d[s]=0;
    priority_queue<pair<ll,ll> >q;
    q.push(mp(0,s));
    while(q.size()){
    
    
        ll u=q.top().se;
        q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u];i;i=a[i].next){
    
    
            ll v=a[i].v,w=a[i].w;
           if(d[v]>d[u]+w){
    
    
          //printf("qwq %lld\n",d[v]);      //松弛操作,更新距离
            d[v]=d[u]+w;
           // printf("sad %lld %lld %lld %lld\n",d[u],u,res,d[v]);
            q.push(mp(-d[v],v)); //把更新的距离和点入队,这里距离取负变成小根堆
            }

        }
    }
}
ll pos[2100][1100];
signed main(){
    
    
ll zyx;
read(n);
read(m);// 警铃
ll tot=0;
for(int i=1;i<n;i++){
    
    
  for(int j=i;j<n;j++){
    
    
  //平面标号
  pos[i][j]=++tot;
  }

}
s=tot+1;
zyx=tot+2; //终点
for(int i=1;i<=m;i++){
    
    
ll u,v,w;
char op[5];
read(u);
read(v);
scanf("%s",op);
read(w);
if(op[0]=='L'){
    
    
 if(v==n){
    
    
 add(pos[u][v-1],zyx,w);
 add(zyx,pos[u][v-1],w);
 //链接汇点
 }
 else{
    
     
add(pos[u][v-1],pos[u][v],w);
 add(pos[u][v],pos[u][v-1],w);

 }

}
if(op[0]=='R'){
    
    

 if(u==1){
    
     add(s,pos[u][v-1],w);
 add(pos[u][v-1],s,w);

 //链接s点
 }
 else{
    
    
 add(pos[u][v-1],pos[u-1][v-1],w);
 add(pos[u-1][v-1],pos[u][v-1],w);
 }

}

}

dij();
if(d[zyx]>=inf){
    
    
    printf("-1\n");
    return 0;
}
printf("%lld\n",d[zyx]);

return 0;
}

完美匹配
emmm 由于是个无向图所以要建立双向流量边
(我这个SB又去拆点了发现跑不出来) 直接连个起点 其他的建立双向就OK Dinic跑出来的maxflow除2 (有手就行,就不贴代码了)

https://paste.ubuntu.com/p/zs9vZrGQBF/

二分图的最小点覆盖
X坐标看作左集合 Y左边看着右集合 对1 建立匹配边
maxflow=二分图最小顶点覆盖

https://paste.ubuntu.com/p/C52G3hKrXB/

2-SAT入门题
写WA了 虽然也预感写错了,要开始学新算法了

网络流&&拆边
get新姿势 拆边建图 一开始我不知道怎么处理这个 cost=aix2 的花费
很愚蠢的改了改SPFA里面的东西 发现不对劲 ,后来想了想,拆成容量 w条边,每条边容量为1,花费递增,也就是说第一条边花费为1
co 第二条边的意义就是 运输单位为2的货物 实际上是要花4cost的钱,但是我们拆了边,连同第一条边也就是说 现在第二条边只需要花费3cost的钱,累加,总花费还是不变的,就很妙的把这个计费转化了

#include <bits/stdc++.h>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include<queue>
#include <time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll int
//#define int long long
//#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x & (-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define Re register int
using namespace std;
const int N=500,M=2*1e6+3,inf=2e9;
int x,y,z,w,o=1,n,m,h,t,st,ed,cyf[N],pan[N],pre[N],dis[N],head[N];
ll mincost,maxflow;
struct QAQ{
    
    int w,to,next,flow;}a[M<<1];
queue<int>Q;
inline void read(Re &x){
    
    
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline void add(Re x,Re y,Re z,Re w){
    
    a[++o].flow=z,a[o].w=w,a[o].to=y,a[o].next=head[x],head[x]=o;}
inline void add_(Re a,Re b,Re flow,Re w){
    
    add(a,b,flow,w),add(b,a,0,-w);}
inline int SPFA(Re st,Re ed){
    
    
    for(Re i=0;i<=n+1;++i)dis[i]=inf,pan[i]=0;  //有多少个点就初始化到那个地方去
    Q.push(st),pan[st]=1,dis[st]=0,cyf[st]=inf;
    while(!Q.empty()){
    
    
    	Re x=Q.front();Q.pop();pan[x]=0;
    	for(Re i=head[x],to;i;i=a[i].next)
            if(a[i].flow&&dis[to=a[i].to]>dis[x]+a[i].w){
    
    
                dis[to]=dis[x]+a[i].w,pre[to]=i;
                cyf[to]=min(cyf[x],a[i].flow);
                if(!pan[to])pan[to]=1,Q.push(to);
            }
    }
    return dis[ed]!=inf;
}
inline void EK(Re st,Re ed){
    
    
    while(SPFA(st,ed)){
    
    
    	Re x=ed;maxflow+=cyf[ed],mincost+=(ll)(cyf[ed])*dis[ed];
    	while(x!=st){
    
    //和最大流一样的更新
            Re i=pre[x];
            a[i].flow-=cyf[ed];
            a[i^1].flow+=cyf[ed];
            x=a[i^1].to;
    	}
    }
}
void cle(){
    
    
o=1;
maxflow=0;
mincost=0;
memset(head,0,sizeof(head));

}
signed main(){
    
    
ll k;
while(scanf("%d%d%d",&n,&m,&k)!=EOF){
    
    
   // if(n<=0||m<=0||k<=0)    
cle();
add_(0,1,k,0);
add_(n,n+1,k,0);
for(int i=1;i<=m;i++){
    
    
    ll u,v,w,co;
    read(u);
    read(v);
    read(co);// 花费
    read(w); //容量
    for(int j=1;j<=w;j++){
    
    
    ll ne=(2*j-1)*co;
    add_(u,v,1,ne);

    }

}
st=0;
ed=n+1;
EK(st,ed);
if(maxflow<k){
    
    printf("-1\n");continue;}
printf("%d\n",mincost);
}
return 0;
}

最小环覆盖&&费用流
一个无向图, 每一个点都必须属于一个圈, 并且只能属于一个圈, 求满足要求的最小费用 ; 显然一个点出度入度都为1 我们可以设置流量为1 价值为它的权值 用费用流来求解 最终如果maxflow不等于n 说明无解
无法构成圈 太坑了 有重边没判,一直TLE

#include <bits/stdc++.h>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <string.h>
#include<queue>
#include <time.h>
#include <cstdio>
#include <iostream>
#include <vector>
#define ll int
//#define int long long
//#define inf 0x3f3f3f3f
#define mods 1000000007
#define modd 998244353
#define PI acos(-1)
#define fi first
#define se second
#define lowbit(x) (x & (-x))
#define mp make_pair
#define pb push_back
#define si size()
#define E exp(1.0)
#define fixed cout.setf(ios::fixed)
#define fixeds(x) setprecision(x)
#define Re register int
using namespace std;
const int N=1e5,M=2*1e6+3,inf=1e9+100;
int x,y,z,w,o=1,n,m,h,t,st,ed,cyf[N],pan[N],pre[N],dis[N],head[N];
ll mincost,maxflow;
struct QAQ{
    
    int w,to,next,flow;}a[M<<1];
queue<int>Q;
inline void read(Re &x){
    
    
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline void add(Re x,Re y,Re z,Re w){
    
    a[++o].flow=z,a[o].w=w,a[o].to=y,a[o].next=head[x],head[x]=o;}
inline void add_(Re a,Re b,Re flow,Re w){
    
    add(a,b,flow,w),add(b,a,0,-w);}
inline int SPFA(Re st,Re ed){
    
    
    for(Re i=0;i<=2*n+1;++i)dis[i]=inf,pan[i]=0;  //有多少个点就初始化到那个地方去
    Q.push(st),pan[st]=1,dis[st]=0,cyf[st]=inf;
    while(!Q.empty()){
    
    
    	Re x=Q.front();Q.pop();pan[x]=0;
    	for(Re i=head[x],to;i;i=a[i].next)
            if(a[i].flow&&dis[to=a[i].to]>dis[x]+a[i].w){
    
    
                dis[to]=dis[x]+a[i].w,pre[to]=i;
                cyf[to]=min(cyf[x],a[i].flow);
                if(!pan[to])pan[to]=1,Q.push(to);
            }
    }
    return dis[ed]!=inf;
}
inline void EK(Re st,Re ed){
    
    
    while(SPFA(st,ed)){
    
    
    	Re x=ed;maxflow+=cyf[ed],mincost+=(ll)cyf[ed]*dis[ed];
    	while(x!=st){
    
    //和最大流一样的更新
            Re i=pre[x];
            a[i].flow-=cyf[ed];
            a[i^1].flow+=cyf[ed];
            x=a[i^1].to;
    	}
    }
}

ll e[1100][1100];
void cle(){
    
    
o=1;
maxflow=0;
mincost=0;
memset(head,0,sizeof(head));
memset(e,inf,sizeof(e));
}

signed main(){
    
    
ll tt;
read(tt);
ll ca=0;
while(tt--){
    
    
read(n);
read(m);
ca++;

cle();

for(int i=1;i<=n;i++){
    
    
    add_(0,i,1,0);
    add_(i+n,2*n+1,1,0);
}

for(int i=1;i<=m;i++){
    
    
   ll u,v,w;
   read(u);
   read(v);
   read(w);
   e[u][v]=min(e[u][v],w);
   e[v][u]=e[u][v];
 //  add_(u,v+n,1,w);
 //  add_(v,u+n,1,w);
}

for(int i=1;i<=n;i++){
    
    
    for(int j=1;j<=n;j++){
    
    
      if(i==j){
    
    continue;}
      if(e[i][j]<inf){
    
    

  add_(i,j+n,1,e[i][j]);
 //  add_(j,i+n,1,e[i][j]);
      }
    }
}
st=0;
ed=2*n+1;
EK(st,ed);

if(maxflow!=n){
    
    printf("Case %d: NO\n",ca);
   // printf("NO\n");
 //   continue;
}
else{
    
    
printf("Case %d: %d\n",ca,mincost);
}

}
return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45948940/article/details/107832247