2826: 有趣的遊戲
Time Limit: 2000 MS Memory Limit: 9000 KB
Total Submit: 72 Accepted: 1 Page View: 181
Submit Status Discuss
Description
一天wangshu迷上了一個十分有趣的遊戲,名爲sdfsfgdsfsdfsdfse,在在遊戲裏你需要從一個起始補給點開始去尋找裝備,每一個補給點都有一定價值的裝備,最後從出口補給點出去,這個遊戲十分有趣,所以當你離開一個補給點後這個補給點會重生和原來一樣價值的裝備,當你達到一個補給點後就會立即得到當前補給點價值的獎勵,然後去下一個補給點,當然從一個補給點到下一個補給點的路徑是單向的,你只能沿着這條路過去不能沿着這條路回來,當然你可能會得到無限多的獎勵,到了出口也可以先不出去,繼續去下一個補給點,同樣也可能無法到達出口補給點,無法到達出口點當然是毫無意義的。
Input
第一行兩個數n,m,分別表示有n個補給點,m條路,其中編號爲1的補給點爲起點,編號爲n的補給點爲出口點。 第二行包括n個數依次表示1到n號補給點的可得的獎勵值ai, 接下來mm行每行兩個數,st,en表示可以從補給點st到補給點en。 保證不會出現重邊和自環。
Output
如果可以得到無窮大的獎勵並能出去輸出"Infinitely",如果不能到達出口則輸出"Unreachable",否則輸出能得到的最大獎勵。
3 2
1 2 3
1 2
2 3
3 3
1 2 3
1 2
2 3
3 2
6
Infinitely
Hint
0<n≤5×1e3,0≤m≤1e4 0<ai≤1e7+5,1≤st,en≤n.均爲整數
題意:就是求有向圖點有權邊無權的最長路。
思路:有兩種情況,第一種是可能到不了終點的有可能在路徑上有環,所以不能讓他遇到環就輸出無法到達,一種是可以到達終點但是可能在任意可到達終點上的路徑存在一個環,答案就是無窮大,只要在可以所有能到達終點的路徑上沒有的環纔是可能有最大值,其他不能到達終點的無所謂,注意就算到了終點也是可以繼續走的,如果環裏終點的話也是無窮大,題面說的十分清楚。
題解:這道題最重要的是正確的判環,怎麼處理環,qwy寫了一個暴力的dfs先判斷哪些點可以到終點,不能到終點的標記,第二次dfs只走哪些可以到終點的點,如果遇到環了就還回無窮大,因爲走的點都是可以到終點的,然後過了跑了1500ms,lx也是寫的差不多的dfs好像比不過優化了很多,只有差不多幾百ms,我的標程是暴力spfa更新n次爲環,或者tarjan縮點+spfa,spfa大家都懂吧把大於改成小於就好了,只是這個判環,假如我們這個有向圖沒有環的話,求最大值,一個點的dis更新一定不會超過n次(仔細想一下,的確是這樣),如果有環的這個點一定會更新無窮多次,那麼記錄一個點更新的次數,一旦更新了n次就標記爲環,dis更新爲無窮大,然後無窮大的點的能到的點也一定是可以更新到無窮大的一直更新下去直到隊列爲空。最後查看dis[n],最壞的情況就是每個點更新n次,只有5000個點1w條邊,2000ms,O(n*n)的複雜度完全可以過,標程跑了差不多500ms。然後tarjan縮點+spfa,(還不會tarjan的先去學習下,這也是一個比較重要的算法),先跑一變tarjan吧所有構成環的點縮成一個點,然後跑spfa,只要是環的就直接更新爲無窮大然後,直到循環結束,複雜度爲O(n),我的標程差不多跑了100ms。jxj寫了個tarjan+spfa代碼+其他的長度2800+B的也過了只跑了20ms。
一共39組數據,第一組數據就是5000個點和4999條邊連成了一條線,還有一組是起點連了1500個小環和終點,第21組是140個點9730條邊的超級稠的圖,還有很多錯綜複雜的圖,不過我沒有那麼傷心病狂出網格圖卡spfa。還有一點比賽的時候內存給的是兩個G其實最開始我只打算給9000kb的,然後應洋哥要求改的,現在改回9000kb了,其實作用不大,只能卡你暴力spfa的時候你沒標記在隊,如果你有其他寫法完全卡不了你,如果你暴力spfa沒標記在隊的話跑出來內存爲9700kb,學長用的其他各種方法都在5000kb以下,也不是專門爲了卡你,不過其他比賽的時候出題人一定會造更大更嚴謹的數據卡你,以及給你更嚴格的時間空間限制,主要是想提醒大家以下。
代碼:
暴力spfa更新n次判環:
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const ll linf=8e18+9e17;
const ll mod=1e9+7;
const double e=exp(1.0);
const double pi=acos(-1);
vector<int>v[5005];
int n,a[5005],num[5005]={0};
ll dis[5005]={0};
bool use[5005];
void spfa()
{
queue<int>q;
q.push(1);
use[1]=1;
while(!q.empty())
{
int now,next;
now=q.front();
q.pop();
use[now]=0;
for(int i=0;i<v[now].size();i++)
{
next=v[now][i];
if(dis[next]!=linf&&dis[now]+a[next]>dis[next]){
if(dis[now]==linf)dis[next]=linf;
else dis[next]=dis[now]+a[next];
num[next]++;
if(num[next]>n)dis[next]=linf;
if(!use[next]){
q.push(next);
use[next]=1;
}
}
}
}
}
int main()
{
//freopen("39.out.txt","w",stdout);
//freopen("39.in.txt","r",stdin);
int m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
int st,en;
scanf("%d%d",&st,&en);
v[st].push_back(en);
}
memset(dis,-1,sizeof dis);
dis[1]=a[1];
spfa();
if(dis[n]==linf)printf("Infinitely\n");
else if(dis[n]==-1)printf("Unreachable\n");
else printf("%d\n",dis[n]);
return 0;
}
tarjan縮點+spfa:
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const ll linf=8e18+9e17;
const int mod=1e9+7;
const double e=exp(1.0);
const double pi=acos(-1);
ll dis[5005];
int a[5005],low[5005],dfn[5005],tim,cnt/*,belong[5005]*/;
bool instack[5005],use[5005];
stack<int>s;
vector<int>v[5005];
//vector<int>v1[maxn];
void tarjan(int st)
{
low[st]=dfn[st]=++tim;
instack[st]=1;
s.push(st);
for(int i=0;i<v[st].size();i++)
{
int next=v[st][i];
if(!dfn[next]){
tarjan(next);
if(low[next]<low[st])low[st]=low[next];
}
else if(instack[next]&&dfn[next]<low[st])low[st]=dfn[next];
}
if(low[st]==dfn[st])
{
cnt++;
int now=inf;
while(now!=st)
{
now=s.top();
s.pop();
instack[now]=0;
//belong[now]=cnt;
//v1[cnt].push_back(now);
}
}
}
void spfa()
{
queue<int>q;
q.push(1);
use[1]=1;
while(!q.empty())
{
int now=q.front();
q.pop();
use[now]=0;
for(int i=0;i<v[now].size();i++)
{
int next=v[now][i];
if(dis[next]!=linf&&dis[now]+a[next]>dis[next]){
if(dis[now]==linf||low[now]==low[next])dis[next]=linf;
else dis[next]=dis[now]+a[next];
if(!use[next]){
q.push(next);
use[next]=1;
}
}
}
}
}
int main()
{
//freopen("39.in.txt","r",stdin);
int n,m,st,en;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&st,&en);
v[st].push_back(en);
}
tarjan(1);
memset(dis,-1,sizeof dis);
dis[1]=a[1];
spfa();
if(dis[n]==linf)printf("Infinitely\n");
else if(dis[n]==-1)printf("Unreachable\n");
else printf("%lld\n",dis[n]);
return 0;
}