zoukankan      html  css  js  c++  java
  • PKU 1932 XYZZY(Floyd+Bellman||Spfa+Floyd)

    题目大意:原题链接

    给你一张图,初始你在房间1,初始生命值为100,进入每个房间会加上那个房间的生命(可能为负),问是否能到达房间n。(要求进入每个房间后生命值都大于0)

    解题思路:

    解法一:Floyd+Bellman

    1.Floyd先判断图是否连通,不连通则直接失败

    2.Bellman Ford然后跑最长路,判断是否有正环或者有正通路

    #include<cstdio>
    #include<cstring>
    using namespace std;
    int n,val[110],d[110];
    bool graph[110][110],link[110][110];
    int main()
    {
        int i,j,k,cnt,id;
        while(scanf("%d",&n),n!=-1){
            memset(d,-1,sizeof(d));
            memset(val,0,sizeof(val));
            memset(link,false,sizeof(link));
            memset(graph,false,sizeof(graph));
            for(i=1;i<=n;i++){
                scanf("%d%d",&val[i],&cnt);
                while(cnt--){
                    scanf("%d",&id);
                    graph[i][id]=true;
                    link[i][id]=true;//用于判断任意两点间的连通性
                }
            }
            //Floyd判断连通性
            for(k=1;k<=n;k++){
                for(i=1;i<=n;i++){
                    for(j=1;j<=n;j++){
                        if(link[i][k]&&link[k][j])
                            link[i][j]=true;
                    }
                }
            }
            if(!link[1][n]){
                printf("hopeless
    ");
                continue;
            }//必须加上这个
            link[n][n]=true;
            //Bellman-ford求最长路径
            d[1]=100;    
            for(k=1;k<=n;k++){//遍历每一个节点 
                bool sign=true;
                for(i=1;i<=n;i++){//遍历每一条边 
                    for(j=1;j<=n;j++){//j,n必须是连通的,并且前一个点d[i]为正 
                        if(graph[i][j]&&link[j][n]&&d[j]<d[i]+val[j]&&d[i]>0){
                            d[j]=d[i]+val[j];
                            sign=false;
                        }
                    }            
                }//如果d[j]已经不能更新了,说明最长路已经查找完毕,即不存在正环,退出循环 
                if(sign) break;
            }
            if(k>n||d[n]>0) printf("winnable
    ");//有正环或者有正通路
            else printf("hopeless
    ");
        }
    }

     解法二:Spfa+Floyd

    1.Spfa先判正环+跑最长路,以及判断是否存在正通路

    2.若d[n]<=0,则Floyd然后根据存在正环以及是否连通起点和终点判断是否会成功到达n点

    #include<cstdio>  
    #include<cstring>  
    #include<queue> 
    #define inf 0x3f3f3f3f
    using namespace std;  
    int n,p,num[110];//num[u]表示u入队次数 
    int val[110],d[110];    
    bool in[110],link[110][110];
    queue<int> que; 
    bool Spfa_floyd(int u)  
    {  
        for(int i=1;i<=n;i++){
            d[i]=-inf;
            in[i]=0,num[i]=0;
        } 
        while(!que.empty()) que.pop();//que定义为全局变量就得清空队列 
        que.push(u);  
        in[u]=true;  
        num[u]=1,d[u]=100;  
        while(!que.empty()){  
            u=que.front();  
            que.pop(); 
            in[u]=false;  
            if(num[u]>n){
                p=u;
                break;//Spfa某节点入队次数大于n则有正环 
            }
            for(int v=1;v<=n;v++){  
                if(link[u][v]&&d[u]+val[v]>0&&d[u]+val[v]>d[v]){  
                    d[v]=d[u]+val[v];//最长路  
                    if(!in[v]){  
                        que.push(v);  
                        in[v]=true;  
                        num[v]++;  
                    }  
                }         
            }  
        }
        if(d[n]>0) return true;  
        else{  
            for(int k=1;k<=n;k++)  
                for(int i=1;i<=n;i++)  
                    for(int j=1;j<=n;j++)  
                        if(link[i][k]&&link[k][j])  
                            link[i][j]=true;   
            if(num[p]>n&&link[1][p]&&link[p][n])
                return true;//如果存在正环,并且连接起点和终点  
            return false;  
        }  
    }  
      
    int main()  
    {  
        while(scanf("%d",&n),n!=-1){  
            memset(link,0,sizeof(link));  
            memset(val,0,sizeof(val));  
            for(int i=1;i<=n;i++){  
                int cnt,id;  
                scanf("%d%d",&val[i],&cnt);  
                for(int j=1;j<=cnt;j++){  
                    scanf("%d",&id);  
                    link[i][id]=true;  
                }  
            }  
            if(Spfa_floyd(1)) puts("winnable");  
            else puts("hopeless");  
        }    
    } 
  • 相关阅读:
    数据库
    poj上关于回文的题目
    最长上升子序列
    [CodeForces]914D Bash and a Tough Math Puzzle
    [HAOI2011]problem a
    Arc123 D
    [Cnoi2020]线性生物
    [USACO17FEB]Why Did the Cow Cross the Road III P
    ABC 210
    CF1111D Destroy the Colony
  • 原文地址:https://www.cnblogs.com/freinds/p/6437997.html
Copyright © 2011-2022 走看看