201703-4地铁修建 终于找到WA点

修改后100分

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector>
#include<string>
#include<limits.h>
#include<cmath>
#include<map>
#include<queue>
#include<set>
#define iter(i,start,end) for(int (i)=(start);(i)<(end);(i)++)
#define vi vector<int> 
using namespace std;

struct edge
{
    int from ,to ,wei;
    edge(int a,int b,int c):from(a),to(b),wei(c){};
};

const int maxnode=100000;
const int maxedge=200000;
const int cmax = 1000000 + 1;
int n,m;
int par[maxnode];
vector<edge>edges;

bool cmp(edge a,edge b){return a.wei < b.wei;}

void init();
void addedge(int from ,int to ,int wei);
void solve();
int findp(int node);
bool dfs(int cur,int par);

int main()
{
    // freopen("201703-4.txt","r",stdin);
    while(scanf("%d %d",&n,&m)==2)
    {
        init();
        solve();
    }
    return 0;
}

void solve()
{
    // bool start=false,end=false;
    for(int i=0;i<edges.size();i++)
    {
        edge temp=edges[i];
        int v=temp.from,u=temp.to,wei=temp.wei;
        int pv=findp(v),pu=findp(u);
        if(pv!=pu)
        {
            par[pv]=pu;
            // if(v==0 || u==0 ) start=true;
            // if(v==n-1 || u==n-1 )   end=true;
            // if(start && end ) 
            if(findp(0) ==findp(n-1))
            {
                cout<<edges[i].wei<<endl;
                break;
            }
        }
    }
}

void init()
{
    edges.clear();
    int from,to,wei;
    for(int i=0;i<m;i++)
    {
        scanf("%d %d %d",&from,&to,&wei);
        edges.push_back(edge(from-1,to-1,wei));
    }

    sort(edges.begin(),edges.end(),cmp);

    iter(i,0,n)
        par[i]=i;
}


int findp(int node)
{
    return par[node]==node?node:par[node]=findp(par[node]);
}

之前一直WA,是因为对Kruskal算法不够了解,导致之前solve函数写成这样:

void solve()
{
    bool start=false,end=false;
    for(int i=0;i<edges.size();i++)
    {
        edge temp=edges[i];
        int v=temp.from,u=temp.to,wei=temp.wei;
        int pv=findp(v),pu=findp(u);
        if(pv!=pu)
        {
            par[pv]=pu;
            if(v==0 || u==0 ) start=true;
            if(v==n-1 || u==n-1 )   end=true;
            if(start && end ) 
            //if(findp(0) ==findp(n-1))
            {
                cout<<edges[i].wei<<endl;
                break;
            }
        }
    }
}

也就是说我给起点和终点做了一个记号,一旦他们两个点都被merge了,那么就说明我最小生成树既扩到了起点,也扩到了终点,也就是说我起点找到了到终点的一条路,此时我就可以break并输出当下的路径的长度,就是起点到终点路上最长的弧了。

看起来似乎很对。。。实际上有可能起点和终点分别被merge在两个不同的集合中,如果我们把整个生成树全部生成出来,那么这两个集合最终一定会merge到一起,但是我们中途退出了,就不能保证这两个集合被merge到了一起。也就是说,此时退出,起点和终点之间还不一定有通路….所以,最正确的做法应该是起点和终点的parent都是一样的(两者在同一个union的充要条件)才退出。

猜你喜欢

转载自blog.csdn.net/Hesy_H/article/details/82288958