模拟赛20181016 Uva 1040 状压+搜索 2005 ACM world final problem c
题目的隐含条件将这道题指向了最小生成树;
利用类似prim的方法,枚举所有子图并判断是否包含询问点,如果包含那么可以更新答案;
边统计边更新,且由于更新一定是向更多的点状态下更新,所以一定可以统计到答案,不至于到全部是inf的情况
再更新答案时记录ps,pe两个变量分别表示此状态最后一次更新前的状态,边,会在寻找路径时用到
最后统计到的答案ans,走到初始的t,路径中打下vis标记后再从头dfs沿着vis打过的走下去,并在路径中遇到叶子节点时顺便将走过的路径放入vector
最后利用vector输出即可
#include<bits/stdc++.h> #define rep(i,x,y) for(register int i=x;i<=y;i++) #define dec(i,x,y) for(register int i=x;i>=y;i--) using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} const int N=25; const int M=500; const int inf=0x3f3f3f3f; vector<int> v[N]; int n,t,m,q,x,all,ans,mx,ask[N]; int dp[1<<21],ps[1<<21],pe[1<<21]; bool vis[N]; int head[N],tot=1; struct node{int v,w,next;bool vis;}e[N*N<<1]; void insert(int u,int v,int w){ e[++tot]=(node){v,w,head[u],0};head[u]=tot; e[++tot]=(node){u,w,head[v],0};head[v]=tot;} inline int count(int x){ int ans=0;while(x) ans++,x-=x&(-x);return ans;} int s[N],top; void dfs(int u,int f){ s[++top]=u; if(vis[u]){ dec(i,top,1) v[u].push_back(s[i]);} //将目前的记录顺序放入vector for(int i=head[u];i;i=e[i].next){ int v=e[i].v; if(v==f||e[i].vis==0) continue; dfs(v,u); }--top; } int main(){ freopen("travel.in","r",stdin); freopen("travel.out","w",stdout); n=read(),t=read(),m=read(); rep(i,1,m){int u=read(),v=read(),w=read();insert(u,v,w);} q=read();rep(i,1,q) x=read(),all|=(1<<(x-1)),vis[x]=1,ask[i]=x; //all 记录全部的询问点的集合 memset(dp,inf,sizeof dp);dp[1<<(t-1)]=0;ans=inf; //利用含t的集合更新答案,最后包含的集合一定有t rep(i,0,(1<<n)-1){ if((i&all)==all){//更新答案的集合包含 if(dp[i]<ans){ ans=dp[i];mx=i; }else if(dp[i]==ans){ if(count(i)<count(mx))//比较集合点数多少 mx=i; }continue; } for(int j=1;j<=n;j++)if((1<<(j-1))&i){ for(int k=head[j];k;k=e[k].next){ //沿着边更新答案 int v=e[k].v,w=e[k].w; if((1<<(v-1))&i) continue; if(dp[i|(1<<(v-1))]>dp[i]+w) dp[i|(1<<(v-1))]=dp[i]+w, ps[i|(1<<(v-1))]=i,pe[i|(1<<(v-1))]=k; //ps代表i上一个状态转移来的集合(点集), //pe代表 i上一次转移的边 } } } printf("distance = %d\n",ans); //利用已有标记爬回去 while(mx!=(1<<(t-1))) e[pe[mx]].vis=1,mx=ps[mx]; dfs(t,0);//再正着下来,记录顺序,放入vector rep(i,1,q){ for(int j=0;j<v[ask[i]].size()-1;j++) printf("%d-",v[ask[i]][j]); printf("%d\n",v[ask[i]][v[ask[i]].size()-1]);} return 0;}
模拟赛搬的就是这道,本地A了但是提交UVA wa掉了,OJ实在太麻烦所以就咕咕咕了(喵喵喵),如果有ctrl c的同学可能会比较惨,不怪我了...haha
完结撒花