1. 程式人生 > >[POI2007]旅遊景點atr

[POI2007]旅遊景點atr

想要 iostream 上一個 AS print ram typedef ++ 我不

Description
FGD想從成都去上海旅遊。在旅途中他希望經過一些城市並在那裏欣賞風景,品嘗風味小吃或者做其他的有趣的事情。經過這些城市的順序不是完全隨意的,比如說FGD不希望在剛吃過一頓大餐之後立刻去下一個城市登山,而是希望去另外什麽地方喝下午茶。幸運的是,FGD的旅程不是既定的,他可以在某些旅行方案之間進行選擇。由於FGD非常討厭乘車的顛簸,他希望在滿足他的要求的情況下,旅行的距離盡量短,這樣他就有足夠的精力來欣賞風景或者是泡MM了^_^.整個城市交通網絡包含N個城市以及城市與城市之間的雙向道路M條。城市自1至N依次編號,道路亦然。沒有從某個城市直接到它自己的道路,兩個城市之間最多只有一條道路直接相連,但可以有多條連接兩個城市的路徑。任意兩條道路如果相遇,則相遇點也必然是這N個城市之一,在中途,由於修建了立交橋和下穿隧道,道路是不會相交的。每條道路都有一個固定長度。在中途,FGD想要經過K(K<=N-2)個城市。成都編號為1,上海編號為N,而FGD想要經過的N個城市編號依次為2,3,…,K+1.舉例來說,假設交通網絡如下圖。FGD想要經過城市2,3,4,5,並且在2停留的時候在3之前,而在4,5停留的時候在3之後。那麽最短的旅行方案是1-2-4-3-4-5-8,總長度為19。註意FGD為了從城市2到城市4可以路過城市3,但不在城市3停留。這樣就不違反FGD的要求了。並且由於FGD想要走最短的路徑,因此這個方案正是FGD需要的。

Input
第一行包含3個整數N(2<=N<=20000),M(1<=M<=200000),K(0<=K<=20),意義如上所述。
之後有q條限制,每次給一對\(x_i,y_i\),代表\(x_i\)要在\(y_i\)之前休息過

Output
只包含一行,包含一個整數,表示最短的旅行距離。

Sample Input
8 15 4
1 2 3
1 3 4
1 4 4
1 6 2
1 7 3
2 3 6
2 4 2
2 5 2
3 4 3
3 6 3
3 8 6
4 5 2
4 8 6
5 7 4
5 8 6
3
2 3
3 4
3 5

Sample Output
19

HINT
技術分享圖片


上圖為題中所給出的例子

這題我不想說什麽,題目輸入描述都不講清楚……看到k<=20,這不直接上狀壓嗎
把1~k+1這些點之間的距離去全部處理出來,然後對於每個點記上一個限制,就可以愉快地用狀壓DP了
有K=0的情況,被坑了

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
typedef
long long ll; typedef unsigned int ui; typedef unsigned long long ull; inline int read(){ int x=0,f=1;char ch=getchar(); for (;ch<‘0‘||ch>‘9‘;ch=getchar()) if (ch==‘-‘) f=-1; for (;ch>=‘0‘&&ch<=‘9‘;ch=getchar()) x=(x<<3)+(x<<1)+ch-‘0‘; return x*f; } inline void write(int x){ if (x>=10) write(x/10); putchar(x%10+‘0‘); } const int N=2e4,M=2e5,K=20; int pre[(M<<1)+10],now[N+10],child[(M<<1)+10],val[(M<<1)+10]; int h[N+10],deep[N+10]; bool vis[N+10]; int dis[K+5][K+5],f[21][1<<K],v[K+5]; int n,m,k,tot,Ans=inf; void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;} void SPFA(int x){//預處理,dijkstra會快一些,但是我懶 memset(vis,0,sizeof(vis)); memset(deep,63,sizeof(deep)); int head=0,tail=1; h[1]=x,vis[x]=1,deep[x]=0; while (head!=tail){ if (++head>N) head=1; int Now=h[head]; for (int p=now[Now],son=child[p];p;p=pre[p],son=child[p]){ if (deep[son]>deep[Now]+val[p]){ deep[son]=deep[Now]+val[p]; if (!vis[son]){ if (++tail>N) tail=1; vis[h[tail]=son]=1; } } } vis[Now]=0; } for (int i=1;i<=k+1;i++) dis[x][i]=deep[i]; dis[x][0]=deep[n]; } void dp(){ memset(f,63,sizeof(f)); for (int i=1;i<=k;i++) if (!v[i]) f[i][1<<(i-1)]=dis[1][i+1]; for (int sta=1;sta<1<<k;sta++){ for (int i=1;i<=k;i++){ if ((f[i][sta]==inf)||(!(sta&(1<<(i-1))))) continue; for (int j=1;j<=k;j++){ if (((v[j]&sta)==v[j])&&(!(sta&(1<<(j-1))))){ f[j][sta|(1<<(j-1))]=min(f[j][sta|(1<<(j-1))],f[i][sta]+dis[i+1][j+1]); } } } } } int main(){ n=read(),m=read(),k=read(); for (int i=1;i<=m;i++){ int x=read(),y=read(),z=read(); join(x,y,z),join(y,x,z); } if (!k){SPFA(1);printf("%d\n",deep[n]);return 0;}//特判 for (int i=1;i<=k+1;i++) SPFA(i); int q=read(); for (int i=1;i<=q;i++){//由於他要經過的點是2~k+1,所以處理起來會有點小惡心 int x=read(),y=read(); v[y-1]|=1<<(x-2); } dp(); for (int i=1;i<=k;i++) Ans=min(Ans,f[i][(1<<k)-1]+dis[i+1][0]); printf("%d\n",Ans); }

[POI2007]旅遊景點atr