比赛 |
近期练习题回顾 |
评测结果 |
RRRRRRRRRR |
题目名称 |
逃离农场 |
最终得分 |
0 |
用户昵称 |
明天 |
运行时间 |
0.003 s |
代码语言 |
C++ |
内存使用 |
34.92 MiB |
提交时间 |
2018-10-29 09:04:06 |
显示代码纯文本
#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
struct node
{
int to,w,next;
};
const int N=100000+5,M=200000+5;
int n,m,K,mm,h[N],len;
node e[M];
int d[N],f[N][51],ans;
bool used[N][51];
template<class T>
inline void Read(T &x)
{
char ch;
while(ch=getchar(),ch<'0' || ch>'9'); x=ch-'0';
while(ch=getchar(),ch>='0' && ch<='9') x=x*10+ch-'0';
}
inline void Add(int i, int j, int w)//建图
{
len++; e[len].to=j; e[len].w=w; e[len].next=h[i]; h[i]=len;
}
int h2[N],len2;
node e2[M];
inline void Add2(int i, int j, int w)//建反图
{
len2++; e2[len2].to=j; e2[len2].w=w; e2[len2].next=h2[i]; h2[i]=len2;
}
void init()
{
memset(h,-1,sizeof(h)); memset(e,-1,sizeof(e)); len=0;
memset(h2,-1,sizeof(h2)); memset(e2,-1,sizeof(e2)); len2=0;
Read(n); Read(m); Read(K); Read(mm);
for (int k=0; k<m; k++)
{
int i,j,w; Read(i); Read(j); Read(w); Add(i,j,w); Add2(j,i,w);
}
}
int tdp(int u, int left)//u表示当前点,left表示当前的k还有多少剩余
{
if (left<0 || left>K) return 0;
if (used[u][left])
{
used[u][left]=false;//出现0环:路径长度不变,又回到当前点
return -1;
}
if(f[u][left]!=-1) return f[u][left];//记忆化
int ret=0; used[u][left]=true;//出现过当前状态
for (int i=h2[u]; ~i; i=e2[i].next)//搜索反图
{
int v=e2[i].to;
int t=tdp(v,(d[u]+left-e2[i].w)-d[v]);//d[u]+left-e2[i].w就是到v的最长距离,减去d[v],就是机动长度
if (t==-1)
{
used[u][left]=false;
return -1;
}
ret=(ret+t)%mm;
}
used[u][left]=false;
if (u==1 && left==0) ret++;
f[u][left]=ret;//f[i][j]表示从n到i的距离<=最短距离+j 的方案数
return ret;
}
int front,tail,q[N];
bool visited[N];
void spfa()//求出d数组:d[i]表示1到结点i的最短距离
{
memset(d,0x3f,sizeof(d)); memset(visited,false,sizeof(visited));
front=0; tail=1; q[tail]=1; d[1]=0; visited[1]=true;
while(front!=tail)
{
front=(front+1)%n;
int u=q[front]; visited[u]=false;
for (int i=h[u]; ~i; i=e[i].next)
{
int v=e[i].to;
if (d[v]>d[u]+e[i].w)
{
d[v]=d[u]+e[i].w;
if (!visited[v])
{
tail=(tail+1)%n; q[tail]=v; visited[v]=true;
}
}
}
}
}
void work()
{
spfa();
ans=0; memset(f,-1,sizeof(f)); memset(used,false,sizeof(used));//枚举使用 共同的f数组
for (int i=0;i<=K;i++)//枚举:0-k,将上限转为定值
{
int t=tdp(n,i);
if (t==-1) {ans=-1; return;}
ans=(ans+t)%mm;
}
}
void print()
{
printf("%d\n",ans);
}
int main()
{
freopen("2017park.in","r",stdin); freopen("2017park.out","w",stdout);
int T; scanf("%d",&T);
while(T--)
{
init(); work(); print();
}
return 0;
}