Codeforces C. A単純なタスク(圧縮状態DP)

件名の説明:

 シンプルなタスク
テストあたりの時間制限
2秒
テストごとのメモリ制限
256メガバイト
入力
標準入力
出力
標準出力

これでシンプルなグラフ、出力の単純なサイクル数を考えます。単純サイクルは繰り返さない頂点またはエッジを有するサイクルです。

入力

入力の最初の行は二つの整数含まN及びM1≤  N  19≤、0≤  M頂点とグラフのエッジのそれぞれ数- )。後続の各M個のラインが二つの整数含ま及びB、(1≤  、  Bの  ≤の  N ≠  B)を示すことが頂点Bは無向エッジによって接続されています。頂点の任意の対を接続する複数のエッジが全く存在しません。

出力

出力与えられたグラフにおけるサイクル数。

入力
コピー
4 6 
1 2
1 3
1 4
2 3
2 4
3 4
出力
コピー
7
注意

例グラフはクリークであり、長さ3の4サイクル及び長さ4の3つのサイクルを含んでいます。

アイデア:

図要件は、一方のエッジによって接続された各2つの頂点間のいくつかの図環、内輪があり判断の対象です。

リングANS ++は、第二の出会いの頂点が始まり、深さ優先探索を、各頂点の深い検索を行う、最後に繰り返しによるリング留守/ = 2、答えに:始まります。しかし、これはタイムアウトます。

1-3-2-4-1 1-4-2-3-1と実際に同じリング、同じ頂点が、異なる繰り返して:回答ツリー下の繰り返し計算の多数が、それを引き起こします環の頂点から出発して繰り返すことができます

次に、DPのDPはかろうじてこの検索のような生命を維持するために暴力を使用することができ、DPはありません、この生活の中では不可能です、

[U] DP [S]で保存されたバイナリ形式の中の現在のポイントへのアクセス状況を示すために、[U] [S] DPと、圧縮DPの状態を考慮して、このアクセス状態を示し、到着する点Uの方法どのように多く、sはゼロバイナリ右端位置がない場合は、どのようにそれの開始点を算出する(3から始まる、例えば100100のような)、パスの起点に対応しますか?バイナリ0 = __起点の終わりに開始の数を計算するために導入されたブログ投稿__builtin_ctzはbuiltin_ctz(S)+1の位置である思い出します。

初期条件を考慮し、D [1 <<(I-1)] [I] = 1(のみ一点のみに独自のアクセスポイント、独自の方法で表される場合)。

次の状態遷移は、状態遷移がDP [S] [U]は=和として書くことができる(DP [S] [I] | G [i]が[U] == 1)、I Uからの方向に、

私に方向Uに書き込むことができ、DPの[S'] [i]は+ = DP [S] [U](G [U] [i]を== 1 &&私!=スタート&& 1 <<(I-1)&S == 0)(S'= 1 <<(I-1)| S)、即ち、iおよびuはエッジを有し、iは出発点ではなく、位置i番目における状態s iが発生していない場合、更新s'i値。

それの端部は、状態遷移時間と、UからIに見出された結果は、私が出発点であり、対応する状態S iは、説明がループを形成している、一度出現したビット。これは、ANS + = DP [S] [U]です。

理解を容易にするために、栗を与えます

図今:唯一つの環がACEFを形成し、前記GFEDCBA、

G:GFEDCBA

S「0 1 1 0 1 0 1(S バイナリ表現)、現在の状態がこれをSと仮定」、I 1(起点)が始めから、初期状態s(ないS')、進行中の状態遷移があった有しますこれは、次に横断する状態(S')、

私は最終的に私はマップを通過するとき、のに横断Fの出会いのポイント、と彼はポイントのエッジを接続していることがわかった、とAが頂点である、との点は、その後、訪問されました!まで待ちます それにリング!

U 1 101 3への出発点として、CAなどが接続され、(なぜ考える)、アルゴリズムはリングとして頂点を結ぶ2つの直線エッジを有することに注意してくださいも1の3辺を有することが見出され、もでさ前に、との出発点で、我々はそれがのリングだと思いました。最後にそこにいくつかの側面が直接、数輪以上に接続されている、マイナスほとんど変化が一方向に1回、2回繰り返されることになるがあるということですので、失います

注意:由于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 - シンプルなタスク、HTTPS://blog.csdn.net/C20191904/article/details/81513904

 

おすすめ

転載: www.cnblogs.com/zhanhonhao/p/11238502.html