CodeForces 11D A Simple Task (DP解哈密顿路径数目)

该博客介绍了一种解决给定简单图中简单循环数目的问题,特别是寻找长度大于等于3的哈密顿路径。通过动态规划(DP)方法来计算,避免重复计数,并提供了一个优化技巧。文章内容包括题目描述、解题思路和相关代码实现。
摘要由CSDN通过智能技术生成
D. A Simple Task
time limit per test
3 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 ≤ 190 ≤ 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 ≤ na ≠ 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.

Sample test(s)
input
4 6
1 2
1 3
1 4
2 3
2 4
3 4
output
7
Note

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


题意:

求一个图中(节点个数小于20)长度大于等于三的哈密顿路径数目。


思路:

点数不多,类似TSP,用状压dp解决。

dp[i][j]表示状态为i时,以j结尾的路径条数。

如果下一个点能回到已经走过的一个点中,那么就是一个回路了。

为了避免重复计算,回到的点为走过的最小的点。(这是一个优化,少了枚举最小点这个循环)

长度为2的哈密顿路径会计算到,可以不做处理,最后减去边的条数即可,每个环会算两遍,最后要除以2.


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#define maxn 205
#define MAXN 100005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std;

ll n,m,ans,flag,cnt,tot;
ll mp[20][20],dp[1<<19][19];

int first(int s)
{
    for(int i=0;i<n;i++)
    {
        if(s&(1<<i)) return i;
    }
}
void solve()
{
    ll i,j,t,k,p,u,v,s;
    ans=0;
    tot=(1<<n)-1;
    memset(dp,0,sizeof(dp));
    for(i=0;i<n;i++)
    {
        dp[1<<i][i]=1;
    }
    for(i=1; i<=tot; i++)
    {
        for(j=0; j<n; j++)
        {
            if(dp[i][j]==0) continue ;
            p=first(i);
            for(k=p; k<n; k++)
            {
                if(j==k||mp[j][k]==0) continue ;
                if(i&(1<<k))
                {
                    if(k==p) ans+=dp[i][j];
                }
                else
                {
                    s=i|(1<<k);
                    dp[s][k]+=dp[i][j];
                }
            }
        }
    }
    ans-=m;
    ans/=2;
    printf("%I64d\n",ans);
}
int main()
{
    ll i,j,t;
    while(~scanf("%I64d%I64d",&n,&m))
    {
        memset(mp,0,sizeof(mp));
        ll u,v;
        for(i=1; i<=m; i++)
        {
            scanf("%I64d%I64d",&u,&v);
            u--,v--;
            mp[u][v]=mp[v][u]=1;
        }
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值