I - Xtreme NP-hard Problem?! Gym - 101806X 暴力+思維
阿新 • • 發佈:2018-12-11
題目連結:http://codeforces.com/gym/101806/problem/X
題意:
給你n個點m條邊,要求你求出走k步到點n的最短路。
做法:
因為min(n,m,k)<=5,所以很明顯,當k>=n||k>m||k>5時,直接就是-1輸出,所以只要處理k<=5的情況,具體的情況我也很難形容,這裡貼一個部落格,覺得寫的挺好。https://blog.csdn.net/qq_41552508/article/details/82351819
爆搜程式碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1000005; struct edge{ int to,next; ll val; }e[maxn<<1]; int n,m,k,x,y,head[maxn],now,vis[maxn]; ll w,ans; void add(int u,int v,ll w){ e[now].to=v,e[now].next=head[u]; e[now].val=w,head[u]=now++; } void dfs(int now,int times,ll val){ if(val>=ans) return ; if(now==n){ if(times==k){ ans=min(ans,val); } return ; } if(times>=k) return ; for(int i=head[now];~i;i=e[i].next){ int t=e[i].to; if(vis[t]) continue; vis[t]=1; dfs(t,times+1,val+e[i].val); vis[t]=0; } } int main(){ memset(head,-1,sizeof(head)); scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;i++){ scanf("%d%d%lld",&x,&y,&w); add(x,y,w); add(y,x,w); } if(k>=n||k>m||k>5) { printf("-1\n"); return 0; } ans=8e17; vis[1]=1; dfs(1,0,0); if(ans==8e17) printf("-1\n"); else printf("%lld\n",ans); return 0; }
學習程式碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1000005; const int inf=1e9+7; struct node{ int to,next; ll val; }e[maxn<<1]; struct edge{ int u,v; ll w; }ed[maxn]; int n,m,k,x,y,head[maxn],now,nume; ll w,ans; ll dist1[maxn][3],dist2[maxn][3]; int pre1[maxn][3],pre2[maxn][3]; void add(int u,int v,ll w){ e[now].to=v,e[now].next=head[u]; e[now].val=w,head[u]=now++; } int ck(int a,int b,int op1,int op2){ if(dist1[a][op1]==inf||dist2[b][op2]==inf) return 0; int fa=pre1[a][op1],fb=pre2[b][op2]; if(fa==1||fa==n||fb==1||fb==n||a==1||b==1||a==n||b==n) return 0; if(fa==fb||fa==b||fb==a||fa==-1||fb==-1||a==b) return 0; return 1; } void doit(int a,int b,int op1,int op2,ll w){ if(ck(a,b,op1,op2)) ans=min(ans,dist1[a][op1]+dist2[b][op2]+w); } void deal(){ for(int i=1;i<=n;i++){ for(int j=0;j<3;j++){ pre1[i][j]=pre2[i][j]=-1; dist1[i][j]=dist2[i][j]=inf; } } for(int j=head[1];~j;j=e[j].next){ int u=e[j].to; ll val1=e[j].val; if(u==n||u==1) continue; for(int i=head[u];~i;i=e[i].next){ int v=e[i].to; ll val2=e[i].val; if(v==1||v==n||v==u) continue; if(dist1[v][0]>val1+val2){ dist1[v][2]=dist1[v][1],pre1[v][2]=pre1[v][1]; dist1[v][1]=dist1[v][0],pre1[v][1]=pre1[v][0]; dist1[v][0]=val1+val2,pre1[v][0]=u; } else if(dist1[v][1]>val1+val2){ dist1[v][2]=dist1[v][1],pre1[v][2]=pre1[v][1]; dist1[v][1]=val1+val2,pre1[v][1]=u; } else if(dist1[v][2]>val1+val2){ dist1[v][2]=val1+val2,pre1[v][2]=u; } } } for(int j=head[n];~j;j=e[j].next){ int u=e[j].to; ll val1=e[j].val; if(u==n||u==1) continue; for(int i=head[u];~i;i=e[i].next){ int v=e[i].to; ll val2=e[i].val; if(v==1||v==n||v==u) continue; if(dist2[v][0]>val1+val2){ dist2[v][2]=dist2[v][1],pre2[v][2]=pre2[v][1]; dist2[v][1]=dist2[v][0],pre2[v][1]=pre2[v][0]; dist2[v][0]=val1+val2,pre2[v][0]=u; } else if(dist2[v][1]>val1+val2){ dist2[v][2]=dist2[v][1],pre2[v][2]=pre2[v][1]; dist2[v][1]=val1+val2,pre2[v][1]=u; } else if(dist2[v][2]>val1+val2){ dist2[v][2]=val1+val2,pre2[v][2]=u; } } } for(int i=1;i<=nume;i++){ int u=ed[i].u,v=ed[i].v; ll w=ed[i].w; for(int i=0;i<3;i++) for(int j=0;j<3;j++) doit(u,v,i,j,w); for(int i=0;i<3;i++) for(int j=0;j<3;j++) doit(v,u,i,j,w); } } int main(){ memset(head,-1,sizeof(head)); scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;i++){ scanf("%d%d%lld",&x,&y,&w); add(x,y,w); add(y,x,w); ed[++nume].u=x,ed[nume].v=y,ed[nume].w=w; } if(k>=n||k>m||k>5) { printf("-1\n"); return 0; } ans=8e17; while(k<5){ add(n,n+1,0);add(n+1,n,0); ed[++nume].u=n,ed[nume].v=n+1,ed[nume].w=0; n++,k++; } deal(); if(ans==8e17) printf("-1\n"); else printf("%lld\n",ans); // return 0; }