UVA 10917

来源:互联网 发布:mac背光键盘不亮 编辑:程序博客网 时间:2024/05/16 18:39

     这道题的意思是,起点是1,终点是2,从1走到2,对于一条边(a,b),只有当存在一条从b出发的到2的路径长小于任何从a出发的路径长,我们才能走,问走到2的方案数。首先我们考虑,如果存在一条b出发的路径,那一定是b到2的最短路,而从a出发到2的路径的最小值也是a到2的最短路,那么我们可以以2为起点做一遍最短路,然后我们枚举边,如果对于一条边(u,v),dis[u]>dis[v],我们就在新图中加入u-->v,可以知道新图是一个DAG,因为如果成环的话,我们可以推出矛盾,这样我们在DAG上DP算方案数即可。

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define maxn 1005#define maxm 200005int last[maxn][2],pre[maxm][2],other[maxm][2],len[maxm][2];int dis[maxn],n,m,l,que[maxm+5],rd[maxn],dp[maxn];bool vis[maxn];void connect(int x,int y,int z,int opt){l++;pre[l][opt]=last[x][opt];last[x][opt]=l;other[l][opt]=y;len[l][opt]=z;}void spfa(void){int h=0,t=1;que[1]=2;while (h!=t) {h=h%maxm+1;int u=que[h];vis[u]=0;for (int p=last[u][0];p;p=pre[p][0]) {int v=other[p][0];if (dis[v]>dis[u]+len[p][0]) {dis[v]=dis[u]+len[p][0];if (!vis[v]) {t=t%maxm+1;que[t]=v;vis[v]=1;}}}}}int main(){while (1) {scanf("%d",&n);if (n==0) break;scanf("%d",&m);memset(last,0,sizeof last);l=0;memset(dis,127,sizeof dis);dis[2]=0;memset(dp,0,sizeof dp);memset(rd,0,sizeof rd);for (int i=1;i<=m;i++) {int a,b,c;scanf("%d%d%d",&a,&b,&c);connect(a,b,c,0);connect(b,a,c,0);}spfa();for (int i=1;i<=n;i++) for (int p=last[i][0];p;p=pre[p][0]) {int v=other[p][0];if (dis[v]<dis[i]) {connect(i,v,0,1);rd[v]++;}}int h=1,t=0;for (int i=1;i<=n;i++) if (rd[i]==0) que[++t]=i;while (h<=t) {int u=que[h];h++;for (int p=last[u][1];p;p=pre[p][1]) {int v=other[p][1];rd[v]--;if (rd[v]==0) que[++t]=v;}}dp[2]=1;for (int i=n;i>=1;i--) {int u=que[i];for (int p=last[u][1];p;p=pre[p][1]) {int v=other[p][1];dp[u]+=dp[v];}}printf("%d\n",dp[1]);}return 0;}



0 0
原创粉丝点击