版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/87916543
Problem
题目描述
给定一个n个点m条边的有向图,有k个标记点,要求从规定的起点按任意顺序经过所有标记点到达规定的终点,问最短的距离是多少。
输入格式
第一行5个整数n、m、k、s、t,表示点个数、边条数、标记点个数、起点编号、终点编号。
接下来m行每行3个整数x、y、z,表示有一条从x到y的长为z的有向边。
接下来k行每行一个整数表示标记点编号。
输出格式
输出一个整数,表示最短距离,若没有方案可行输出-1。
题解
设经过的第i个标记点的编号为 ,则所经过的路径是 .
我们所求的就是上面这一条路径的长度最小。
观察数据范围,我们发现k很小,那个我们可以对每一个 跑一边最短路,再对起点跑一边最短路。
现在每两个 和起点之间的最短路径搞好了,需要考虑顺序了;我们可以用状压DP解决。
设 表示经过的点数状态为 ,以 结尾的路径最小值。
此时有状态转移方程:
至于初始化,暴力搞一遍每一个 到起点的具体即可。
最后的结果为:
代码如下:
#include<bits/stdc++.h>
using namespace std;
int n,m,ans=0;
int s[60000];
int in[60000];
queue<int>q;
vector<int>a[60000];
int main(void)
{
freopen("triangle.in","r",stdin);
freopen("triangle.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",s+i);
scanf("%d",&m);
for (int i=1,x,y,z;i<=m;++i)
{
scanf("%d %d %d",&x,&y,&z);
if (z==1 || z==2) a[x].push_back(y),in[y]++;
if (z==4 || z==5) a[y].push_back(x),in[x]++;
}
for (int i=1;i<=n;++i)
if (!in[i]) q.push(i);
while (q.size())
{
int now=q.front();
q.pop();
for (int i=0;i<a[now].size();++i)
{
int next=a[now][i];
in[next]--;
if (!in[next]) q.push(next);
if (!s[now]) s[next]^=1;
}
if (!s[now]) ans++;
}
printf("%d\n",ans);
return 0;
}