[USACO08JAN]电话线Telephone Lines 洛谷P1948

来源:互联网 发布:马赛克复原软件 编辑:程序博客网 时间:2024/05/16 18:47

洛谷P1948

关键信息整理:给出一个有n个点的图,要求连接一些端点,使得终点和起点连通且第k-1长的路尽可能短。
解题思路:一看到第k-1长的路尽可能的短就想到二分答案,那么如何控制第k-1长的路呢?用sort肯定是不现实的,耗时耗空间。
不妨正好借二分答案,把大于答案长度的路设置成1,小于等于的设置成0,跑一个SPFA,因为可以连接无数个,这是个可行的方案。
然后就贴源代码了,这道题一开始的转化比较难,确定方向是二分答案后一切都变得美好了~

#include<iostream>#include<cstdio>#include<queue>#include<cstring>#include<cstdlib>using namespace std;/*const&int*/const int maxconn=100001;const int maxpow=10001;int ans;int totpow,totcon,freex;/*链式前向星*/struct ll{    int to;    int nxt;    int truevalue;//真正的长度     int spfavalue;//spfa时的01 }edge[maxconn];int head[maxpow],cnt=0;/*二分答案*/int l,r;#define mid ((l+r)>>1)//这里要注意位运算的优先度,反正多加括号不会错 /*SPFA*/queue<int> spfa;int quehead;bool exist[maxpow];int way[maxpow];/*init*/void setValue(){    for(int i=1;i<=totpow;++i) way[i]=100001;//memset不靠谱,这是上次做题时的血泪教训     for(int i=1;i<=totpow;++i)    {        for(int j=head[i];j!=-1;j=edge[j].nxt)        {            if(edge[j].truevalue<=mid)/*因为是判断答案是否可行,因此小于mid的直接变成0*/            {                edge[j].spfavalue=0;            }            else            {                edge[j].spfavalue=1;            }        }    }}/*链式前向星*/void addEdge(int x,int y,int value){    edge[++cnt].nxt=head[x];    edge[cnt].to=y;    edge[cnt].truevalue=value;    head[x]=cnt;}/*二分答案*/bool check(){    if(way[totpow]<=freex)    {        return 1;    }    else    {        return 0;    }}/*SPFA*/void SPFA(){    /*正常的SPFA 中间的nowpay<=freex剪枝可以忽略不计*/    spfa.push(1);    way[1]=0;    int will,nowpay;    while(spfa.empty()==0)    {        quehead=spfa.front();        spfa.pop();        exist[quehead]=0;        for(int i=head[quehead];i!=-1;i=edge[i].nxt)        {            will=edge[i].to;            nowpay=way[quehead]+edge[i].spfavalue;            if(way[will]>nowpay&&nowpay<=freex)            {                way[will]=nowpay;                if(exist[will]==0)                {                    spfa.push(will);                    exist[will]=1;                }            }        }    }}int main(){    memset(head,-1,sizeof(head));//别问我为什么这里有memset     l=0;r=-1;    scanf("%d%d%d",&totpow,&totcon,&freex);    int x,y,far;    for(int i=1;i<=totcon;++i)//链式前向星储存     {        scanf("%d%d%d",&x,&y,&far);        addEdge(x,y,far);        addEdge(y,x,far);        r=max(r,far);    }    ans=-1;    while(l<=r)//二分答案搜索     {        setValue();//预处理spfavalue         SPFA();//spfa        if(check())//判断答案是否可行         {            ans=mid;            r=mid-1;        }        else        {            l=mid+1;        }    }    printf("%d\n",ans);    return 0;}
阅读全文
1 0