• hdu6026 dijkstra


    题目链接:http://icpc.njust.edu.cn/Problem/Hdu/6026/

    题意大致是:给定一个图,要求删边使他变成树,使得每个点到0的距离就是原图中0到这个点的最短路径。其实就是最短路树。

    证明1: 对于每个结点我们只要知道有多少条路径到它的距离是最短路长度,记为cnt,那么就有cnt条边连着前驱结点,首先,能保证的是每个点都是0能够到达的,所以前驱结点一定是全部都能到达的,就是他们的d一定存在,所以我们只要删除cnt-1条边,留下一条就能建成最短路树。对于每个结点,我们扫描之后按照乘法规则将方案数相乘即可。

    下面分三种情况来证明这是一棵树

    ①、假设有一个结点p连着一个结点q,有dis[q]<dis[p]+edge[p][q],那么这就构成了一个圈,我们删除edge[p][q]就变成了无圈而且从0都能到达这两个结点,对于其他边,我们也可以这样删除。

    ②、假设有一个结点p连着一个结点q,有dis[q]=dis[p]+edge[p][q],我们从证明1中知道这样的p只会有一个,因为这样的边我们的算法中已经删的只剩下一条。所以这种情况不构成圈。

    ③、假设有一个结点p连着一个结点q,有dis[q]>dis[p]+edge[p][q],与dis[q]是q的最短路长度矛盾。

    综上:算法完成之后的图成为了树。

    代码如下:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef unsigned int ui;
     4 typedef long long ll;
     5 typedef unsigned long long ull;
     6 #define pf printf
     7 #define mem(a,b) memset(a,b,sizeof(a))
     8 #define prime1 1e9+7
     9 #define prime2 1e9+9
    10 #define pi 3.14159265
    11 #define lson l,mid,rt<<1
    12 #define rson mid+1,r,rt<<1|1
    13 #define scand(x) scanf("%llf",&x) 
    14 #define f(i,a,b) for(int i=a;i<=b;i++)
    15 #define scan(a) scanf("%d",&a)
    16 #define mp(a,b) make_pair((a),(b))
    17 #define P pair<int,int>
    18 #define dbg(args) cout<<#args<<":"<<args<<endl;
    19 #define inf 0x3f3f3f3f
    20 const int maxn=100;
    21 const int mod=1e9+7;
    22 int n,m,t;
    23 int d[maxn],edge[maxn][maxn];
    24 void dijkstra(int src)
    25 {
    26     priority_queue<P,vector<P> ,greater<P> >q;
    27     f(i,0,n-1)d[i]=inf;
    28     d[src]=0;
    29     q.push(mp(0,src));
    30     while(!q.empty())
    31     {
    32         P now=q.top();
    33         q.pop();
    34         int u=now.second;
    35         if(d[u]<now.first)continue;
    36         f(i,0,n-1)
    37         {
    38             if(edge[u][i]&&d[i]>d[u]+edge[u][i])
    39             {
    40                 d[i]=d[u]+edge[u][i];
    41                 q.push(mp(d[i],i));
    42             }
    43         }
    44     }
    45 }
    46 int main()
    47 {
    48     //freopen("input.txt","r",stdin);
    49     //freopen("output.txt","w",stdout);
    50     std::ios::sync_with_stdio(false);
    51     while(scan(n)!=EOF)
    52     {
    53         char c;
    54         f(i,0,n-1)
    55             f(j,0,n-1)
    56             {
    57                 scanf(" %c",&c);
    58                 edge[i][j]=c-'0';
    59             }
    60             ll ans=1;
    61             dijkstra(0);
    62             f(i,1,n-1)
    63             {
    64                 int cnt=0;
    65                 f(j,0,n-1)
    66                 {
    67                     if(edge[i][j]&&(d[j]+edge[j][i]==d[i]))cnt++;
    68                 }
    69                 ans=(ans*cnt)%mod;
    70             }
    71             pf("%lld
    ",ans);
    72     }
    73     
    74  } 

     

  • 相关阅读:
    DNS放大攻击
    Java并发编程(四):并发容器(转)
    关注商业价值
    样式小记
    应用程序优化
    查看当前的连接和锁
    重命名你的数据库
    转:对XML插入操作
    对数据的分页再一次思考
    不浪费自己的时间,同时也不浪费别人的时间
  • 原文地址:https://www.cnblogs.com/randy-lo/p/12551836.html
Copyright © 2020-2023  润新知