XYZZY HDU1317

2 篇文章 0 订阅
1 篇文章 0 订阅

题意:一个游戏,从1号房间走到N号房间,每个房间都会有个能量值(可能为正,可能为负),每进入一个房间,房间的能量值就会加到玩家身上。

思路:求这个图的最长路,如果存在正环且正环能够到达终点则赢,或者到达终点时能量值大于0且整个过程中能量值大于0则赢。判断能不能到达用 Floyd 算法,求最长路用 BellmanFord 算法或 SPFA 算法。

下面是用 BellmanFord 和 Floyd 算法实现的。
自己实现过程中遇到的问题有:忘了每次初始化 G 数组为 0 。。。还有就是BellmanFord 用的不熟,,细节地方出了差错。
代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;

const int INF = 1000000;
const int MAXN = 110;

struct Edge{
    int from, to;
    Edge(){}
    Edge(int a, int b):from(a),to(b){}
};

int n;
int G[MAXN][MAXN];
int value[MAXN];
int d[MAXN];
vector<Edge> edges;

void Floyd()
{
    for(int k=1; k<=n; k++){
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                G[i][j] |= G[i][k]&G[k][j];  //Floyd算法判断能否到达
            }
        }
    }
}

bool BellmanFord(int s)
{
    for(int i=1; i<=n; i++) d[i] = -INF;
    d[1] = 100;

    for(int i=1; i<n; i++){
        for(int j=0; j<edges.size(); j++){
            int from = edges[j].from;
            int to = edges[j].to;
            if(d[to] < d[from]+value[to] && d[from]+value[to]>0){   //只有新的值大于 0 才能松弛
                d[to] = d[from]+value[to];
            }
        }
    }

    for(int i=0; i<edges.size(); i++){
        int from = edges[i].from;
        int to = edges[i].to;
        if(d[to] < d[from]+value[to] && d[from]+value[to]>0 && G[to][n]){   //如果存在环,且这个环能够到达终点那么 winnable
            return true;
        }
    }

    return d[n] > 0;
}

void Init()
{
    memset(G, 0, sizeof(G));
    edges.clear();
}

int main()
{
    //freopen("in.txt", "r", stdin);
    while(scanf("%d", &n) == 1 && n!=-1){
        Init();
        for(int i=1; i<=n; i++){
            scanf("%d", &value[i]);
            int m;
            scanf("%d", &m);
            while(m--){
                int x;
                scanf("%d", &x);
                G[i][x] = 1;
                edges.push_back(Edge(i, x));
            }
        }

        Floyd();

        if(G[1][n]){
            if(BellmanFord(1)){
                printf("winnable\n");
            }
            else{
                printf("hopeless\n");
            }
        }
        else{
            printf("hopeless\n");
        }
    }
    return 0;
}

下面是用 Flyod 和 SPFA 算法写的

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<stack>
#include<queue>
#include<utility>
#include<vector>
#include<cmath>
#include<set>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;

const int INF = 1000000;
const int MAXN = 110;

struct Edge{
    int from, to;
    Edge(){}
    Edge(int a, int b):from(a),to(b){}
};

int n;
int G[MAXN][MAXN];
int value[MAXN];
int d[MAXN];
int time[MAXN];
bool inq[MAXN];
vector<Edge> edges;
vector<int> M[MAXN];

void Floyd()
{
    for(int k=1; k<=n; k++){
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                G[i][j] |= G[i][k]&G[k][j];  //Floyd算法判断连通性
            }
        }
    }
}

bool SPFA(int s)
{
    for(int i=1; i<=n; i++) d[i] = -INF;
    d[s] = 100;
    memset(inq, false, sizeof(inq));
    memset(time, 0, sizeof(time));

    queue<int> que;
    que.push(s);
    inq[s] = true;

    while(!que.empty()){
        int tmp = que.front();  que.pop();

        inq[tmp] = false;

        for(int i=0; i<M[tmp].size(); i++){
            Edge &e = edges[M[tmp][i]];
            if(d[e.to] < d[e.from]+value[e.to] && d[e.from]+value[e.to]>0 ){
                d[e.to] = d[e.from]+value[e.to];
                if(!inq[e.to]){
                    inq[e.to] = true;
                    if(++time[e.to] > n+1) {return G[e.to][n];}
                    que.push(e.to);
                }
            }
        }
    }

    return d[n] > 0;
}

void Init()
{
    memset(G, 0, sizeof(G));
    for(int i=0; i<MAXN; i++){
        M[i].clear();
    }
    edges.clear();
}

int main()
{
    //freopen("in.txt", "r", stdin);
    while(scanf("%d", &n) == 1 && n!=-1){
        Init();

        for(int i=1; i<=n; i++){
            scanf("%d", &value[i]);
            int m;
            scanf("%d", &m);
            while(m--){
                int x;
                scanf("%d", &x);
                G[i][x] = 1;
                edges.push_back(Edge(i, x));
                M[i].push_back(edges.size()-1);
            }
        }

        Floyd();

        if(G[1][n]){
            if(SPFA(1)){
                printf("winnable\n");
            }
            else{
                printf("hopeless\n");
            }
        }
        else{
            printf("hopeless\n");
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值