51nod 1326 遥远的旅途
一个国家有N个城市,这些城市被标为0,1,2,...N-1。这些城市间连有M条道路,每条道路连接两个不同的城市,且道路都是双向的。一个小鹿喜欢在城市间沿着道路自由的穿梭,初始时小鹿在城市0处,它最终的目的地是城市N-1处。小鹿每在一个城市,它会选择一条道路,并沿着这条路一直走到另一个城市,然后再重复上述过程。每条道路会花费小鹿不同的时间走完,在城市中小鹿不花时间逗留。路程中,小鹿可以经过一条路多次也可以经过一个城市多次。给定城市间道路的信息,问小鹿是否有一种走法,从城市0出发到达城市N-1时,恰好一共花费T个单位的时间。如果存在输出“Possible”,否则输出“Impossible”。
注意,小鹿在整个过程中可以多次经过城市N-1,只要最终小鹿停在城市N-1即可。
例如样例中小鹿的行程可以是0->1->2->0->2.
Input
多组测试数据,输入的第一行含一个整数caseT,表示测试数据个数,1<=caseT<=3. 之后有caseT组相同结构的测试数据,每组测试数据构成如下: 第一行三个整数,N,M,T,且2<=N<=50,1<=M<=50,1<=T<=1,000,000,000,000,000,000(即 10^18). 之后M行,每行三个整数Ai,Bi,Di,表示城市Ai与Bi间有一条双向道路,且小鹿穿越这条路要花费Di的时间。其中,0<=Ai,Bi<N,1<=Di<=10000。
Output
每组测试数据一行输出,如果存在题目所述路径输出“Possible”,否则“Impossible”,不含引号。
Input示例
1 3 3 25 0 2 7 0 1 6 1 2 5
Output示例
Possible
题解:
这个题目暴力dp,一定连空间都开不下,但这个已经是凑数模型的唯一状态,没有什么其他办法,所以,一定要想着题目中的其他限制或者说性质。
因为这个是一个图论模型,所以转移就十分有限制,只能走边权,所以我们可以发现要凑出这个数,就一定是先到n号点,然后通过走一条边2*k遍来达到目的,所以我们可以列出式子,(t-dis(1~n))%2*k==0(k为和n号点相连的某条边的边权))
转化成t%(2*k)==dis(1~n)%(2*k)。用这个式子,我们就只要看是否存在一条到n的路径,使得路径的边权和%2*k等于一个定值t%(2*k)。
因为这个题目和模数有关,所以我们要把取摸的结果写入状态,dp[i][j]表示处于i节点,从一号点到i号点的花费和%(2*k)(选择的边权)等与k的最小花费,那么转移就是dp[to][(j+quan)%mod]=min(dp[now][j]+quan).
可以说是有限制的凑数问题吧,因为这个题目是一个图,有后效性,所以spfa。
代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #include <queue> #define MAXN 200 #define MAXN2 20100 #define ll long long using namespace std; ll dis[MAXN][MAXN2]; bool have[MAXN][MAXN2]; struct edge{ int first; int next; int to; int quan; }a[MAXN*2]; struct node{ int now,ti; }; queue<node> q; int n,m,num=0;ll t,mod; void addedge(int from,int to,int quan){ a[++num].to=to; a[num].quan=quan; a[num].next=a[from].first; a[from].first=num; } void spfa(){ memset(dis,127,sizeof(dis)); memset(have,0,sizeof(have)); while(!q.empty()) q.pop(); have[1][0]=1,dis[1][0]=0; q.push((node){1,0}); while(!q.empty()){ node hh=q.front();q.pop(); int now=hh.now,t=hh.ti; have[now][t]=0; for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to,quan=a[i].quan,tt=(t+quan)%mod; if(dis[to][tt]>dis[now][t]+quan){ dis[to][tt]=dis[now][t]+quan; if(!have[to][tt]){ have[to][tt]=1; q.push((node){to,tt}); } } } } } void work(){ scanf("%d%d%lld",&n,&m,&t); memset(a,0,sizeof(a));int flag=0;num=0; for(int i=1;i<=m;i++){ int x,y,z;scanf("%d%d%d",&x,&y,&z);x++,y++; addedge(x,y,z),addedge(y,x,z); } for(int i=a[n].first;i;i=a[i].next){ int quan=a[i].quan; mod=quan*2; spfa(); if(dis[n][t%mod]<=t){ printf("Possible\n");flag=1; break; } } if(!flag){ printf("Impossible\n"); } } int main() { int t;cin>>t; while(t--){ work(); } return 0; }