最小奖励 MINAW

【题目描述】

Jzabc更是一个狂热的“驴友”,这次他想去一个诡异的地方。这个地方有n个村庄,编号为1n。此刻他在1号村,他想到n号村。这n个村子之间有m条单向道路。通过某些道路时,可能需要花费一些钱作为“买路钱”,可是通过一些道路时不仅不用交钱反而会得到某些奖励。当然两个村庄之间可能有多条直接相连的道路,但是每条道路只能通过一次。这些村庄有这样的特性,从任何一个村庄出发,沿着任一条路径走都不会回到出发点。找到一条路径从1号到n号,他需要计算一共得到多少奖励,一共交了多少过路钱。如果奖励的钱数大于交的过路钱数,那么称这样一套路径可以得到奖励,反之吐过前者小雨后者,那么这样的路径需要花费,如果二者相等,那么Jzabc不会选择。不会出现所有的路径两者都相等,现在请你帮忙找到一条路径,使得到的奖励最小(为什么不是奖励最大?或花费最少?花费最大?),并输出最小奖励。如果找不到一条路径使其得到奖励,那么就找一条路径使其得到的花费最大(为何不是最小花费?),并输出最大花费。

【输入格式】

第一行,两个用空格隔开的正整数nm

以下m行,每行三个正整数x,y,w,描述一条路的信息,中间用空格隔开,其中x表示道路的起点,y表示终点;若w为负,则是通过磁条道路交的买路钱数目,若w为正,则表示这条路奖励的钱数;w不为零,且其绝对值不大于10

【输出格式】

一个整数,若有最小奖励则输出,否则输出最大花费;

【输入样例】

3 4

1 2 2

2 3 -1

2 3 3

1 3 -1

【输出样例】

1

【输入样例】

3 4

1 2 2

2 3 -3

2 3 -5

1 3 -2

【输出样例】

3

【数据规模】

对于20%的数据,满足n<=20,   m<=200

对于50%的数据,满足n<=50,   m<=2000

对于100%的数据,满足n<=100,   m<=20000



相当于有两问

1.能否得到奖励

2.如果能 求最小奖励

   如果不能 求最大花费


第一问 可以spfa求最长路 得到length[m]
若m<0 spfa求最短路 得到d[m]输出

若m>0 不好处理了就。。。

关于m>0 一开始是把每一个可能的与1的距离扔到set里

然后取出这些元素 更新与这个点相连的其他点的距离

这样可以过5个点 卡时可以全过


题解说可以拓扑排序+递推

后来加上拓扑排序+set 还是超5个点 1.5s左右

后来去掉set 用bool数组存可能的距离 就不超时了= =


其实由于数据太弱 直接spfa利用正权边求最短路就可以过了 (-.-)丧心病狂


附上拓扑排序代码 其中拓扑排序是我自己yy的 也不知道对不对...

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
using namespace std;
const int inf=999999999;
const int lim=108;
const int len=20011;

struct self{int x,y,w;}s[len];
int first[len],nxt[len];
bool inq[lim];
queue<int>q;
int longth[lim],d[lim];
int m,n,a,b,c;

void maxspfa()
{
    int a;
    memset(inq,0,sizeof(inq));
    for(a=1;a<=m;a++)longth[a]=-inf;
    longth[1]=0;
    q.push(1);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        inq[u]=0;
        for(int e=first[u];e!=-1;e=nxt[e])
        if(longth[s[e].y]<s[e].w+longth[u])
        {
            longth[s[e].y]=s[e].w+longth[u];
            if(!inq[s[e].y])
            {
                inq[s[e].y]=1;
                q.push(s[e].y);
            }
        }
    }
}

void minspfa()
{
    int a;
    memset(inq,0,sizeof(inq));
    for(a=1;a<=m;a++)d[a]=inf;
    d[1]=0;
    q.push(1);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        inq[u]=0;
        for(int e=first[u];e!=-1;e=nxt[e])
        if(d[s[e].y]>d[u]+s[e].w)
        {
            d[s[e].y]=d[u]+s[e].w;
            if(!inq[s[e].y])
            {
                inq[s[e].y]=1;
                q.push(s[e].y);
            }
        }
    }
}

int rank[lim],into[lim];
void tsort()
{
    int i=0;
    q.push(1);
    while(!q.empty())
    {
        int u=q.front();q.pop();
        i++;rank[i]=u;
        for(int e=first[u];e!=-1;e=nxt[e])
        {
            into[s[e].y]--;
            if(into[s[e].y]==0)
            q.push(s[e].y);
        }
    }
}
bool g[lim][len];
void work()
{
    int a,i;
    for(a=1;a<=m;a++)q.push(rank[a]);
    g[1][10000]=1;
    while(!q.empty())
    {
        int u=q.front();q.pop();
        for(int e=first[u];e!=-1;e=nxt[e])
        {
            for(i=0;i<=20000;i++)
            if(g[u][i])g[s[e].y][i+s[e].w]=1;
        }
    }

    for(i=10001;i<=20000;i++)
    if(g[m][i])
    {
        printf("%d\n",i-10000);
        return;
    }
}
    
int main()
{
    freopen("minaw.in","r",stdin);freopen("minaw.out","w",stdout);
    memset(first,-1,sizeof(first));memset(nxt,-1,sizeof(nxt));
    scanf("%d%d",&m,&n);
    for(a=1;a<=n;a++)
    {
        scanf("%d%d%d",&s[a].x,&s[a].y,&s[a].w);
        into[s[a].y]++;
        nxt[a]=first[s[a].x];
        first[s[a].x]=a;
    }
    maxspfa();
    if(longth[m]<=0)
    {
        minspfa();
        cout<<-d[m]<<endl;
        return 0;
    }
    else
    {
        tsort();
        work();
    }
    return 0;
}
        



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值