并不对劲的bzoj2521:p5039:[SHOI2010]最小生成树
题目大意
有一个\(n\)个点\(m\)条边的有边权的连通无向图,其中有一条边是被指定的。
可以进行的操作是选一条边,把除它以外的边边权-1。
问至少操作多少次,使被指定的边一定会在这张图的最小生成树上。
\(n\leq 500;m\leq800;边权\leq10^6;\)
题解
在进行最小生成树时,边权具体是多少不重要,重要的是边之间的边权大小关系。
所以可以把“除某边以外的所有边边权-1”看成“该边边权+1”。
从kruskal求最小生成树的过程中可以看出,只有当边权小于等于指定的边的边权的边不能让指定的边的端点连通时,指定的边才一定会加入最小生成树。
也就是说,要通过最少的边权+1操作,使所有边权小于等于指定的边的边权的边不能让指定的边的端点连通。
这可以用最小割解决。
代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define LL long long
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 507
#define maxm 3207
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
char ch[20];int f=0;
if(!x){putchar('0'),putchar('\n');return;}
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
}
const int inf=2147483647;
int fir[maxn],nxt[maxm],v[maxm],fl[maxm],cnte;
int n,m,ss,tt,eu[maxm],ev[maxm],ew[maxm],lab,dis[maxn],maxfl,q[maxn],hd,tl;
void ade(int u1,int v1,int fl1)
{
v[cnte]=v1,nxt[cnte]=fir[u1],fl[cnte]=fl1,fir[u1]=cnte++;
v[cnte]=u1,nxt[cnte]=fir[v1],fl[cnte]=0,fir[v1]=cnte++;
}
int getd()
{
rep(i,1,n)dis[i]=-1;dis[ss]=0;q[hd=tl=1]=ss;
while(hd<=tl)
{
int u=q[hd];hd++;
view(u,k)if(fl[k]>0&&dis[v[k]]==-1){dis[v[k]]=dis[u]+1,q[++tl]=v[k];}
}
return dis[tt]==-1?0:1;
}
int getfl(int u,int nowfl)
{
if(!nowfl||u==tt)return nowfl;
int tmp,sum=0;
view(u,k)
{
if(!nowfl)break;
if(fl[k]&&dis[v[k]]==dis[u]+1&&(tmp=getfl(v[k],min(nowfl,fl[k])))>0)
fl[k]-=tmp,fl[k^1]+=tmp,sum+=tmp,nowfl-=tmp;
}
return sum;
}
int main()
{
n=read(),m=read(),lab=read();
rep(i,1,n)fir[i]=-1;
rep(i,1,m){eu[i]=read(),ev[i]=read(),ew[i]=read();if(i==lab)ss=eu[i],tt=ev[i];}
rep(i,1,m)if(i!=lab&&ew[i]<=ew[lab])
{
ade(eu[i],ev[i],ew[lab]-ew[i]+1);
ade(ev[i],eu[i],ew[lab]-ew[i]+1);
}
while(getd())maxfl+=getfl(ss,inf);
write(maxfl);
return (~(0-0)+1);
}