The 2018 ACM-ICPC China JiangSu Provincial Programming Contest - K. Road

JSZKC is the king of his kingdom.

His kingdom has N cities, numbered from 0 to N−1. And the cities are connected by some roads which means you can travel from one city to any other city by roads. Each roads have its length.

However, JSZKC wants to delete some roads(may be 0) and let the kingdom keep the following requirements:

  1. All the cities are still connected.
  2. The number of the rest roads is minimal
  3. For all the cities, its shortest distance to 0 doesn't change.

JSZKC wants to know how many ways to delete roads with these requirements. Two ways are different if one road is deleted in one way while not in the other way.

As the result may be very large, please output the result mod 1000000007.

Input Format

The input file contains several test cases, each of them as described below.

  • The first line of the input contains one integers N (1≤N≤100), giving the cities of the kingdom.
  • The next follows N lines with each line N integers. Let's define the jth integer in the ith line as f[i][j]. Then it's guaranteed that f[i][j]=f[j][i] and 0≤f[i][j]≤9. If f[i][j]>0, then there is a road with length f[i][j] connecting city i and city j. If f[i][j]=0, then there is no road between city i and city j.

There are no more than 100 test cases.

Output Format

One line per case, an integer indicates the answer.

样例输入

2
01
10
4
0123
1012
2101
3210

样例输出

1
6

 

解题思路:

求最短路条数。用Dijkstra计算路程最短时,各点前导点的可能情况,最后相乘即可。

 

AC代码:

#include <bits/stdc++.h>
using namespace std;

#define ms 102
typedef long long ll;


int road[ms][ms];
int n;
ll e[ms]; //记录情况数

ll ModMul(ll a,ll b,ll n)//快速积取模 a*b%n
{
    ll ans=0;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%n;
        a=(a+a)%n;
        b>>=1;
    }
    return ans;
}

void Dijkstra()
{
    int fin[ms]={0}; //判断该点是否已在集合中,为0不在为1在
    int all,i,work;

    struct record
    {
        int length; //到当前点的路径长度
        int pre; //当前距离的前导点
    }dis[ms];

    for(i=1; i<n; i++)
        {
            dis[i].length=road[0][i];
            dis[i].pre=0;
        }
    fin[0]=1;

    int minm;

    for(all=0; all<n; all++) //生成0到其它所有点的最短路
        {
            work=1;
            while(work<n && (fin[work] == 1 || dis[work].length == 0))
            {
                work++;
            }

        	if(work == n)
                break;

            minm = work;

            while(work < n-1)
            {
                work++;
                if(fin[work] == 0 && dis[work].length != 0 && dis[work].length < dis[minm].length)
                minm = work;
            }

            fin[minm] = 1;

            for(i=1; i<n; i++)
            {
                if(fin[i] == 0 && road[minm][i]!= 0)
                {
                    if(dis[i].length == dis[minm].length+ road[minm][i])
                    {
                        e[i]++;
                    }
                    else if(dis[i].length > dis[minm].length+road[minm][i] || dis[i].length==0)
                    {
                        dis[i].length = dis[minm].length + road[minm][i];
                        dis[i].pre = minm;
                        e[i]=1;  //关键,最短路更新后重置e[i]。因为前一个if判断相等时,length不一定最短。
                    }
                }
            }
        }
}

int main()
{
    int i,j;
    while(~scanf("%d",&n))
    {
        ll ans=1;
        char temp[ms];

        for(i=1;i<n;i++)
            e[i]=1;
        memset(road,0,sizeof(road));

        getchar();

        for(i=0;i<n;i++)
        {
            gets(temp);
            for(j=0;j<n;j++)
            {
                road[i][j]=temp[j]-'0';
            }
        }

        Dijkstra();

        for(i=1;i<n;i++)
        {
            ans=ModMul(ans,e[i],1000000007);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值