Challenge program design: codeforces round #776 (Div. 3) g. counting shortcuts

Posted by ThEMakeR on Wed, 09 Mar 2022 10:18:26 +0100

Title portal

Main idea of the title:

Given an undirected graph G without self ring and mu lt iple edges, as well as the starting point and end point S and T, the edge weight is 1, find the path length from S to T < = the number of shortest path length + 1.

Problem solving ideas

Since the edge weight length is constant as 1, the shortest path counting is very simple. It can be done by using bfs, and the front time complexity is stable O(2m). There is no need to use spfa or djstra.
When we get the number of shortest paths, we need to consider how to find the number of shortest paths + 1 for a point.
For point x, set its shortest path length from S as midis, which points will update the number of shortest paths + 1 of this point.
Suppose point x is connected to point y:

  • When the dis of point y > midis, y cannot contribute to x, because the dis of X is the shortest. If the strategy from y to X is adopted, then x is dis+1, which is two distances longer than the shortest path.
  • When dis=midis, it is only 1 larger than the shortest path, which is what we need
  • When dis==midis-1, point x can inherit the number of shortest path + 1 of point y.
  • When dis < midis-1, there is obviously no contribution.

According to this characteristic, we can see that the state update has a certain topological order, so we can recursively update the state from small to large.
Further analysis, which points will update the point with the shortest path length of x?
Can be divided into two sets:

  • Point with shortest path length = = x-1, (inherited)
  • Point with shortest circuit length = = x, (increase)

So whether to inherit first or increase first, or has no effect?
Inherits the number of shortest paths + 1 of the previous node, which means that the number of shortest paths of the previous node needs to be the final state.
What is increased is the number of the shortest paths of the previous node, and the initial bfs of this state has been completed.
Therefore, all States can be transferred by adding and then inheriting.

code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define il (i<<1)
#define ir (i<<1)+1
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
const ll mod = 1e9 + 7;
const int maxn = 2e5 + 5;
inline char nc() { static char buf[1000000], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++; }
inline void read(int &sum) { char ch = nc(); sum = 0; while (ch < '0') ch = nc(); while (ch >= '0') sum = (sum << 3) + (sum << 1) + (ch ^ 48), ch = nc(); }
vector<int>e[maxn],tp[maxn];
ll dp[maxn][2];
void sovle()
{
	int n, m,S,T;
	read(n); read(m);
	read(S); read(T);
	for (int i = 0; i <= n; i++)tp[i].clear(), e[i].clear(),dp[i][1]=dp[i][0]=0;
	for(int i=1;i<=m;i++)
	{
		int u, v;
		read(u); read(v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	/*###############BFS###############*/
	queue<int>q;
	q.push(S);
	vector<int>dis(n + 1, -1);
	dis[S] = 0;
	dp[S][0] = 1;
	while(q.empty()!=1)
	{
		int s = q.front(); q.pop();
		for(auto to:e[s])
		{
			if (dis[to] == -1)dis[to] = dis[s] + 1, dp[to][0] = dp[s][0],q.push(to);
			else if (dis[to] == dis[s] + 1)dp[to][0]+=dp[s][0],dp[to][0]%=mod;
		}
	}
	for (int i = 1; i <= n; i++)tp[dis[i]].push_back(i);
	for(int i=0;i<=n;i++)
	{
		for(auto s:tp[i])
		{
			for(auto to:e[s])
			{
				if(dis[to]==dis[s])dp[to][1] += dp[s][0];/increase
				dp[to][1] %= mod;
			}
		}
		for (auto s : tp[i]) {
			for (auto to : e[s])
			{
				if (dis[to] == dis[s] + 1)dp[to][1] += dp[s][1];/inherit
				dp[to][1] %= mod;
			}
		}
	}
	cout << (dp[T][0] + dp[T][1])%mod << '\n';
}
int main() 
{
	//ios::sync_with_stdio(false);
	int t=1;
	cin >> t;
	//read(t);
	while (t--)sovle();
	return 0;
}

There are few code comments. Welcome to leave a message.

Topics: Algorithm data structure Dynamic Programming Graph Theory codeforce