 /**//*
一個無向圖,n<=3000 , m <= 20000
有k個限制,表示a->b->c不能走, k<= 10^5
求1到n的最短路,不能走過有限制的地方

我猜是bfs,但是不會做,我的思維局限在狀態(tài)是在頂點上,這樣是不夠記錄的
如a->b->a,兩個a的狀態(tài)值是不同的

看了watashi的,DIY群上有人說是以邊為狀態(tài)
dp[pre][now]表示從1到pre->now這條邊經(jīng)過的花費
枚舉now的非限制的鄰接邊擴展
對于判重問題通過去掉邊來做
it = E[u].erase(it)
這樣下次就不會走了 神奇丫!!!!!!!!!!!!

存限制時是用map<pair<int,int>,set<int> > mp
這樣存(a,b,c)比起弄兩個pair好多了!!!
*/
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<list>
#include<set>

using namespace std;

const int MAXN = 10086;
const int INF = 1000000000;

list<short> E[3001];
map<pair<short,short> , set<short> > mp;//(a,b,c)
int dp[3001][3001] ;
short pre[3001][3001];

 void print(int last , int now) {
if(last == -1)return;
print(pre[last][now] , last);
printf("%d ",last);
}

int main()
  {
 for(int n , m, k;~scanf("%d%d%d",&n,&m,&k);) {
 for(int i = 1 ; i <= n; i ++) {
E[i].clear();
}
int a,b,c;
 for(int i = 0 ; i < m ; i++) {
scanf("%d%d",&a,&b);
E[a].push_back(b);
E[b].push_back(a);
}
mp.clear();
 for(int i = 0 ; i < k ; i++) {
scanf("%d%d%d",&a,&b,&c);
mp[make_pair(a,b)].insert(c);
}

fill(dp[1],dp[n+1],INF);

queue<pair<short,short> > Q;
 for(list<short>::iterator it = E[1].begin() ; it != E[1].end() ; it++) {
dp[1][*it] = 1;
pre[1][*it] = -1;
Q.push(make_pair(1,*it));
}
E[1].clear();
 while(!Q.empty()) {
pair<short,short> p = Q.front();
Q.pop();
a = p.first;
b = p.second;
set<short> &iset = mp[p];
 for(list<short>::iterator it = E[b].begin() ; it != E[b].end();) {
 if(iset.count(*it) > 0) {
it++;
}
 else {
dp[b][*it] = dp[a][b] + 1;
pre[b][*it] = a;
Q.push(make_pair(b,*it));
it = E[b].erase(it);//處理判重!!
}
}
}
int ans = INF , ansPre;
 for(int i = 1 ; i < n ; i++) {
 if(dp[i][n] < ans) {
ans = dp[i][n];
ansPre = i;
}
}

if(ans == INF)puts("-1");
 else {
printf("%d\n",ans);
print(ansPre,n);
printf("%d\n",n);
}
}
return 0;
}
|
|
常用鏈接
隨筆分類
Links
搜索
最新評論

|
|