【bzoj1937】[Shoi2004]Mst 最小生成树
程序员文章站
2022-06-29 21:48:55
...
Description
Input
第一行为N、M,其中 表示顶点的数目, 表示边的数目。顶点的编号为1、2、3、……、N-1、N。接下来的M行,每行三个整数Ui,Vi,Wi,表示顶点Ui与Vi之间有一条边,其权值为Wi。所有的边在输入中会且仅会出现一次。再接着N-1行,每行两个整数Xi、Yi,表示顶点Xi与Yi之间的边是T的一条边。
Output
输出最小权值
Sample Input
6 9
1 2 2
1 3 2
2 3 3
3 4 3
1 5 1
2 6 3
4 5 4
4 6 7
5 6 6
1 3
2 3
3 4
4 5
4 6
1 2 2
1 3 2
2 3 3
3 4 3
1 5 1
2 6 3
4 5 4
4 6 7
5 6 6
1 3
2 3
3 4
4 5
4 6
Sample Output
8
【样例说明】
边(4,6)的权由7修改为3,代价为4
边(1,2)的权由2修改为3,代价为1
边(1,5)的权由1修改为4,代价为3
所以总代价为4+1+3=8
修改方案不唯一。
【样例说明】
边(4,6)的权由7修改为3,代价为4
边(1,2)的权由2修改为3,代价为1
边(1,5)的权由1修改为4,代价为3
所以总代价为4+1+3=8
修改方案不唯一。
HINT
1<=n<=50,1<=m<=800,1<=wi<=1000
n-->点数..m-->边数..wi--->边权
st->树边->非树边->ed
把每一条非树边两端的树边找出来,如果树边比非树边小,那就连起来,流量为1,费用为权值差(我是树边-非树边)
跑一遍费用流,记得是最长路,为什么呢?因为我们要修改树边的值使它为最小生成树啊!
好好看吧,我觉得我的代码挺好理解的^-^
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
int x,y,c,d,next,other;
}a[1310000];int len,last[810];
int st,ed;
void ins(int x,int y,int c,int d)
{
int k1,k2;
len++;k1=len;
a[len].x=x;a[len].y=y;a[len].c=c;a[len].d=d;
a[len].next=last[x];last[x]=len;
len++;k2=len;
a[len].x=y;a[len].y=x;a[len].c=0;a[len].d=-d;
a[len].next=last[y];last[y]=len;
a[k1].other=k2;
a[k2].other=k1;
}
int d[810],head,tail,list[810],pre[810];
bool v[810];
int ans;
bool spfa()
{
for(int i=1;i<=ed;i++) d[i]=-999999999;
d[st]=0;
memset(v,false,sizeof(v));v[st]=true;
list[1]=st;head=1;tail=2;
while(head!=tail)
{
int x=list[head];
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(a[k].c>0 && d[y]<d[x]+a[k].d)
{
d[y]=d[x]+a[k].d;
pre[y]=k;
if(v[y]==false)
{
v[y]=true;
list[tail++]=y;
if(tail==ed+1) tail=1;
}
}
}
head++;
if(head==ed+1) head=1;
v[x]=false;
}
if(d[ed]<0) return false;
return true;
}
void get()
{
int x=ed,k,minn=999999999;
while(x!=st)
{
k=pre[x];
minn=min(minn,a[k].c);
x=a[k].x;
}
x=ed;
while(x!=st)
{
k=pre[x];
a[k].c-=minn;
a[a[k].other].c+=minn;
ans+=a[k].d*minn;
x=a[k].x;
}
}
struct bian
{
int x,y,c,next;
}e[810];int lenn,lastt[810];
int map[51][51],num[51][51],tree[51][51];
int n,m;
struct uuu
{
int id,a[810];
uuu(){id=0;}
}w[810];
int f[810];
void dfs(int x,int fa)
{
f[x]=fa;
for(int i=1;i<=w[x].id;i++)
{
if(w[x].a[i]==fa) continue;
dfs(w[x].a[i],x);
}
return ;
}
void build()
{
for(int i=1;i<=m;i++)
{
int x=e[i].x,y=e[i].y;
if(tree[x][y]!=-1) continue;
dfs(y,0);
for(;x!=y;x=f[x])
{
int t=map[x][f[x]]-e[i].c;
if(t>0) ins(tree[x][f[x]],i,1,t);
}
}
for(int i=1;i<=m;i++)
{
if(tree[e[i].x][e[i].y]!=-1) ins(st,num[e[i].x][e[i].y],1,0);
else ins(num[e[i].x][e[i].y],ed,1,0);
}
}
int main()
{
int x,y,c,kk;
scanf("%d%d",&n,&m);
st=m+1;ed=st+1;
memset(num,-1,sizeof(num));
memset(tree,-1,sizeof(tree));
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&c);
map[x][y]=c;map[y][x]=c;
num[x][y]=i;num[y][x]=i;
e[i].x=x;e[i].y=y;e[i].c=c;
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
tree[x][y]=tree[y][x]=num[x][y];
w[x].id++;w[x].a[w[x].id]=y;
w[y].id++;w[y].a[w[y].id]=x;
}
build();
ans=0;
while(spfa()==true) get();
printf("%d\n",ans);
return 0;
}
下一篇: mongoDB身份验证