您的位置:首页 > 其它

bzoj1050: [HAOI2006]旅行comf(最小生成树)

2017-10-27 21:30 155 查看
题目传送门

想了一个多小时就想到一个暴力,结果还真是。。

解法:

先判断st和ed连不连通,不连通就IMPOSSIBLE。

最小生成树可以做。

先按照边权从小到大排序。

然后枚举每条边,以当前这条边作为最小的边,添加比它大的边。

如果添加的边可以使得st和ed连通,那么维护一下答案。

那如果最大的边不一定是st到ed这条路径上面的边怎么办呢。

对于每一条边,添加完之后马上判断st和ed是否连通。

如果这条边添加完后st和ed连通了。

说明这条边肯定在st到ed上。

而又因为这条边是最后一个添加的(边权从小到大),所以这条边肯定是这种方法的最大值。

本想加个优化结果WA了不懂。

路过dalao帮忙看看呗。

代码实现:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
int gcd(int a,int b) {
if(a==0)
return b;
return gcd(b%a,a);
}
struct node {
int x,y,c;
}a[5100];int len;
void ins(int x,int y,int c) {
len++;
a[len].x=x;a[len].y=y;a[len].c=c;
}
bool cmp(node n1,node n2) {
return n1.c<n2.c;
}
int fa[510];
int findfa(int x) {
if(x!=fa[x])
fa[x]=findfa(fa[x]);
return fa[x];
}
int main() {
//freopen("1050.in","r",stdin);
//freopen("1050.out","w",stdout);
int n,m;scanf("%d%d",&n,&m);
len=0;
for(int i=1;i<=m;i++) {
int x,y,c;scanf("%d%d%d",&x,&y,&c);
if(x!=y)
ins(x,y,c);
}
int st,ed;scanf("%d%d",&st,&ed);
for(int i=1;i<=n;i++)
fa[i]=i;
int t=0;
sort(a+1,a+1+len,cmp);
for(int i=1;i<=len;i++) {
int xx=findfa(a[i].x),yy=findfa(a[i].y);
if(xx!=yy) {
fa[xx]=yy;
t++;
if(findfa(st)==findfa(ed))
break;
}
}
if(findfa(st)!=findfa(ed)) {
printf("IMPOSSIBLE\n");
return 0;
}
double ans=999999999.0;
int aa,bb;
for(int i=1;i<=len;i++) {
for(int j=1;j<=n;j++)
fa[j]=j;
int mx=0;
for(int j=i;j<=len;j++) {
int xx=findfa(a[j].x),yy=findfa(a[j].y);
if(xx!=yy)
fa[xx]=yy;
/*if(double(a[j].c)/double(a[i].c)>ans)
break;*/    //这句优化有任何问题?
if(findfa(st)==findfa(ed)) {
mx=a[j].c;
break;
}
}
if(findfa(st)!=findfa(ed))
break;
if(ans>double(mx)/double(a[i].c)&&findfa(st)==findfa(ed)) {
ans=double(mx)/double(a[i].c);
aa=mx;bb=a[i].c;
}
}
int d=gcd(aa,bb);
aa/=d;bb/=d;
if(bb==1)
printf("%d\n",aa);
else
printf("%d/%d\n",aa,bb);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: