Deleting Edges
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 263 Accepted Submission(s): 85
Problem Description
Little Q is crazy about graph theory, and now he creates a game about graphs and trees.
There is a bi-directional graph withn nodes,
labeled from 0 to n−1 .
Every edge has its length, which is a positive integer ranged from 1 to 9.
Now, Little Q wants to delete some edges (or delete nothing) in the graph to get a new graph, which satisfies the following requirements:
(1) The new graph is a tree withn−1 edges.
(2) For every verticev(0<v<n) ,
the distance between 0 and v on
the tree is equal to the length of shortest path from 0 to v in
the original graph.
Little Q wonders the number of ways to delete edges to get such a satisfied graph. If there exists an edge between two nodesi and j ,
while in another graph there isn't such edge, then we regard the two graphs different.
Since the answer may be very large, please print the answer modulo109+7 .
There is a bi-directional graph with
Now, Little Q wants to delete some edges (or delete nothing) in the graph to get a new graph, which satisfies the following requirements:
(1) The new graph is a tree with
(2) For every vertice
Little Q wonders the number of ways to delete edges to get such a satisfied graph. If there exists an edge between two nodes
Since the answer may be very large, please print the answer modulo
Input
The input contains several test cases, no more than 10 test cases.
In each test case, the first line contains an integern(1≤n≤50) ,
denoting the number of nodes in the graph.
In the followingn lines,
every line contains a string with n characters.
These strings describes the adjacency matrix of the graph. Suppose the j -th
number of the i -th
line is c(0≤c≤9) ,
if c is
a positive integer, there is an edge between i and j with
length of c ,
if c=0 ,
then there isn't any edge between i and j .
The input data ensure that thei -th
number of the i -th
line is always 0, and the j -th
number of the i -th
line is always equal to the i -th
number of the j -th
line.
In each test case, the first line contains an integer
In the following
The input data ensure that the
Output
For each test case, print a single line containing a single integer, denoting the answer modulo 109+7 .
Sample Input
2 01 10 4 0123 1012 2101 3210
Sample Output
1 6
Source
题意:
n个点,n*2-n条边,删除掉只剩下n-1条边,满住剩下的每个点在原图中都是最短路的存在。
分析:
dij队列优化需要vis,可以避免重复入队的情况,但是不加vis也不会无尽循环下去。
来自某个博客其他人的解法,其实也不需要跑完全图。
说入度乘积我更倾向于说成每个点走法的乘积。(5.15重温这句话发现这句话还是有问题的,到三点的还有一种画法)
dij算法就是求原点到各个点的最短路,也很贴合这道题的性质。那么不同走法之间会有影响吗?只有两个独立事件同时发生没有影响才能相乘。(有问题)
结果是没有影响。原题中说只要存在任意一条不同的边就是不同的图。
dij最短路的原理就是通过不同路来松弛。每种走法的组合一定可以存在一条异边。第三个点也是建立在前面点基础上通过扩展而来。
因为n为50,所以随便哪个最短路算法都能过吧:
正插邻接表加队列的确比反插好写多了。。。
#include <iostream> #include <cstdio> #include <queue> #include <vector> #include <bits/stdc++.h> #define mod 1000000007 using namespace std; typedef long long ll; const int maxn = 100+10; const int INF = 0x3f3f3f3f; char ch[60][60]; int cnt[maxn]; struct node{ int x,d; node(){} node(int a,int b){x=a;d=b;} bool operator < (const node & a) const { return d > a.d; } }; vector<node> eg[maxn]; int dis[maxn]; void Dijkstra(int s) { dis[s]=0; //用优先队列优化 priority_queue<node> q; q.push(node(s,dis[s])); while(!q.empty()) { node x=q.top();q.pop(); //最后一个点就可以跳出了 if(x.x==n-1) break; for(int i=0;i<eg[x.x].size();i++) { node y=eg[x.x][i]; if(dis[y.x]>x.d+y.d) { cnt[y.x] = 1; dis[y.x]=x.d+y.d; q.push(node(y.x,dis[y.x])); } else if(dis[y.x]==x.d+y.d) { cnt[y.x]++; } } } } int main() { // freopen("in.txt","r",stdin); int n; while(~scanf("%d",&n)) { for(int i=0;i<=n;i++) dis[i]=INF; memset(cnt,0,sizeof(cnt)); cnt[0]=1; for(int i=0;i<=n;i++) eg[i].clear(); for(int i=0;i<n;i++) { scanf("%s",ch[i]); for(int j=0;j<n;j++) { if(ch[i][j]!='0') eg[i].push_back(node(j,ch[i][j]-'0')); } } Dijkstra(0); ll ans = 1LL; for(int i = 0; i < n; i++) { ans *= cnt[i]; ans %= mod; } printf("%d ",ans); } return 0; }
一开始超时的,不知道在哪里:
反正以后就用vector写了。。。。
#include <cstdio> #include <cmath> #include <cctype> #include <algorithm> #include <cstring> #include <utility> #include <string> #include <iostream> #include <map> #include <set> #include <vector> #include <queue> #include <stack> typedef long long ll; using namespace std; const int maxn = 60+10; const int INF = 0x3f3f3f3f; //int mp[maxn][maxn]; int first[maxn]; int cnt[maxn]; int num,dis[100]; char ch[60][60]; int vis[60]; #define mod 1000000007 struct Node { int id; int val; }node; struct Edge { int id;//以此点为出边找边 int val; int next; }e[maxn]; void add(int u,int v,int d) { //num边的编号 e[num].id = v; e[num].val = d; e[num].next = first[u]; first[u] = num; num++; } priority_queue<Node> q; bool operator < (Node a,Node b) { return a.val > b.val; } int main() { // freopen("in.txt","r",stdin); int n,m; while(~scanf("%d",&n)) { memset(first,-1,sizeof(first)); memset(cnt,0,sizeof(cnt)); while(!q.empty()) q.pop(); for(int i=0;i<n;i++) { scanf("%s",ch[i]); for(int j=0;j<n;j++) { if(ch[i][j]!='0') add(i,j,ch[i][j]-'0'); } } for(int i = 1; i <= n; i++) { dis[i] = INF; } Node cur; dis[0] = 0; node.id = 0; node.val = 0; q.push(node); cnt[0] = 1; while(!q.empty()) { // if(cur.id == End){ // break; // } cur = q.top(); q.pop(); //i为边的编号 for(int i = first[cur.id]; i != -1; i = e[i].next) { if(dis[e[i].id] > e[i].val+cur.val) { cnt[e[i].id] = 1; dis[e[i].id] = e[i].val+cur.val; node.id = e[i].id; node.val = dis[e[i].id]; q.push(node); } else if(dis[e[i].id] == e[i].val+cur.val) cnt[e[i].id]++; } } ll ans = 1LL; for(int i = 0; i < n; i++) { ans *= cnt[i]; ans %= mod; } // for(int i = 0; i <= n; i++) { // printf("初始点到%d点的距离为%d ",i,dis[i]); // } printf("%d ",ans); } return 0; }