Codeforces C. A Simple Task (compression state dp)

Subject description:

 A Simple Task
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Given a simple graph, output the number of simple cycles in it. A simple cycle is a cycle with no repeated vertices or edges.

Input

The first line of input contains two integers n and m (1 ≤ n ≤ 19, 0 ≤ m) – respectively the number of vertices and edges of the graph. Each of the subsequent m lines contains two integers a and b, (1 ≤ a, b ≤ n, a ≠ b) indicating that vertices a and b are connected by an undirected edge. There is no more than one edge connecting any pair of vertices.

Output

Output the number of cycles in the given graph.

Examples
Input
Copy
4 6
1 2
1 3
1 4
2 3
2 4
3 4
Output
Copy
7
Note

The example graph is a clique and contains four cycles of length 3 and three cycles of length 4.

Ideas:

FIG requirement is subject to a judgment that there are several FIG ring, an inner ring, between every two vertices connected by one edge only.

Beginning: depth-first search, do a deep search for each vertex, the second encounter vertex beginning, ring ans ++; and finally due to repeated ring ans / = 2, the answer. However, this would timeout.

Causes it, a large number of repeated calculations below answer tree: 1-3-2-4-1 and 1-4-2-3-1 actually the same ring, the same vertex are repeated, different starting from the vertex of the ring may be repeated

Then, dp dp is impossible in this life will not dp, can barely use violence to sustain life like this search,

Consider the state of compression DP, with DP [s] [u] to indicate access status to the current point in binary form s stored with, DP [s] [u], indicates this access state, the point u way to arrive how many, where s is not zero binary rightmost position corresponds to the starting point of the path, (such as 100100, starting at 3) how to calculate the starting point of it? Remember the blog post __builtin_ctz introduced to calculate the number of start at the end of a binary 0 = __ starting point is the location of builtin_ctz (s) +1.

Consider the initial conditions, d [1 << (i-1)] [i] = 1 (only in the case represented by its own access point, their own way to only one point).

Next is a state transition, the state transition can be written as dp [s] [u] = sum (dp [s] [i] | G [i] [u] == 1), to a direction from i u,

May be written in a direction u to i, dp [s'] [i] + = dp [s] [u] (G [u] [i] == 1 && i! = Start && 1 << (i-1) & s == 0) (s' = 1 << (i-1) | s), i.e., when i and u have edges, and i is not the starting point, and the state s i in the i th position not occurred, then the update s'i value.

The end of it, if the state transition time, the results found from u to i i is the starting point, and the corresponding state s i bit i has appeared once, description has formed a loop. This is ans + = dp [s] [u].

To facilitate understanding, give a chestnut

FIG now: GFEDCBA, wherein only one ring formed ACEF

G:GFEDCBA

s': 0 1 1 0 1 0 1 (s binary representation), assuming that the current state is this s', I have from 1 (the starting point) began, the initial state s (not s'), ongoing state transition has been this will traverse to the next state (s'),

Wait until I finally traversed to the s' when I traverse the map, F encounter point, and found that he has connected A point edge, and A is an apex, and A point has been visited, then! A ring to it!

Note that the algorithm will have two straight edges that connect vertices as a ring, (think about why), such as CA is connected, as a starting point u 1 to 101 3 are found to have 3 edges of even 1, but also in before, and is the starting point, we thought it was a ring of. So in the end there are several side is directly connected to more than a few rings, minus is that there is little change will be repeated twice, once in one direction, to lose

注意:由于n的数字很小,用比较tricky的思维来看,应该找不到一个多项式算法,因此我们可以设计一个阶层或指数级的算法。有兴趣的同学可以证明该问题是个NP问题。
一个环是由若干个节点以及节点的顺序决定的。若用最暴力的方法统计n个节点的无向图中环的个数,则根据圆排列公式需要枚举O(∑ni=3(i!2i))
个环,每个环用O(n)的时间复杂度检查每个环是否真的存在,因此,总的时间复杂度则为O(n!)。由于该问题的n最大值是19,而19!是一个庞大的数字,所以阶层复杂度的算法是不能够被接受的。

所以数据要开long long

代码:

 1 #include <iostream>
 2 #define max_n 20
 3 using namespace std;
 4 int n;
 5 int m;
 6 int G[max_n][max_n];
 7 long long dp[1<<max_n][max_n];
 8 long long ans = 0;
 9 int st(int n)
10 {
11     return __builtin_ctz(n)+1;
12 }
13 int main()
14 {
15     //cout << __builtin_ctz(4)+1 << endl;
16     cin >> n >> m;
17     for(int i = 0;i<m;i++)
18     {
19         int f,t;
20         cin >> f >> t;
21         G[f][t] = G[t][f] = 1;
22     }
23     for(int i = 1;i<=n;i++)
24     {
25         dp[1<<(i-1)][i] = 1;
26     }
27     long long S = (1<<n)-1;
28     //cout << S << endl;
29     for(int s = 1;s<=S;s++)
30     {
31         for(int u = 1;u<=n;u++)
32         {
33             if(dp[s][u]==0) //没有方法可以按着s到u
34             {
35                 continue;
36             }
37             int start = st(s);
38             //cout << start << endl;
39             for(int i = start;i<=n;i++)
40             {
41                 if(G[i][u])
42                 {
43                     if((s&(1<<(i-1)))&&i==start)
44                     {
45                         ans += dp[s][u];
46                     }
47                     else if(!(s&(1<<(i-1))))
48                     {
49                         long long ss = s|(1<<(i-1));
50                         dp[ss][i] += dp[s][u];
51                     }
52                 }
53             }
54         }
55     }
56     ans -= m;
57     ans /= 2;
58     cout << ans << endl;
59     return 0;
60 }

 

以上还不明白?正常,我可能也没讲太清楚,推荐给你:

餃子,Codeforces A Simple Task 统计简单无向图中环的个数,https://blog.csdn.net/fangzhenpeng/article/details/49078233

还有:C20191904,CodeForces -  A Simple Task,https://blog.csdn.net/C20191904/article/details/81513904

 

Guess you like

Origin www.cnblogs.com/zhanhonhao/p/11238502.html