暴力搜索(HDU 5305,Friends)

来源:互联网 发布:长城软件纳税服务电话 编辑:程序博客网 时间:2024/06/06 10:39

HDU 5305,Friends

1<=n<=8,这个范围的数据不仅可以考虑位压缩更可以阶乘级别的暴力枚举或搜索了。

本题主要和边有关,所以点位压缩没什么好方法,边位压缩也没什么意义,而且边是O(n^2)级别的也不可能压。


那就考虑枚举,首先要思考最坏情况有多少种答案,粗略算一下,发现顶多也就C(8,4)*C(7,3)*C(6,2)*C(5,1)=183750,100组数据可以接受。(事实上高估了很多,毕竟阶乘的东西差一点就差很多,更准确的计算应该是C(7,3)*C(6,2)*C(5,1)=2625左右)。

由于点边之间的关系是一个拓扑结构,所以很难一对一地枚举到所有情况,只能通过搜索加剪枝的方式,看看能不能用较低的搜索量完成枚举。

我们已经知道有效的答案不是很多,接下来就该考虑如何枚举以减少无用的搜索。

既然主要问题是边二选一而不是点,那我们最好考虑枚举边,然后以点为限制条件,为了尽量较少搜索量,限制条件尽量用完,即一个点所连的边的种类必须各占一半。那就在搜索过程中记录以确定的点连边的情况,然后枚举边的选择,一直暴搜就好了,事实上效果很好,暴搜的效率和边的顺序有关,相关的边放在一起剪枝效果更大,比如可以按点顺序来搜,不过都差不多了。


代码:

#include<stdio.h>using namespace std;const int maxn = 10;const int maxm = 100;int n,m;int U[maxm],V[maxm];int id[maxn],a[maxn],b[maxn];int cnt;void dfs(int cur){    if(cur==m+1)    {        cnt++;        return;    }    if(a[U[cur]]<id[U[cur]]&&a[V[cur]]<id[V[cur]])    {        a[U[cur]]++;        a[V[cur]]++;        dfs(cur+1);        a[U[cur]]--;        a[V[cur]]--;    }    if(b[U[cur]]<id[U[cur]]&&b[V[cur]]<id[V[cur]])    {        b[U[cur]]++;        b[V[cur]]++;        dfs(cur+1);        b[U[cur]]--;        b[V[cur]]--;    }}void solve(){    scanf("%d %d",&n,&m);    for(int i=1;i<=n;i++)    {        id[i]=a[i]=b[i]=0;    }    for(int i=1;i<=m;i++)    {        scanf("%d %d",U+i,V+i);        id[U[i]]++;        id[V[i]]++;    }    for(int i=1;i<=n;i++) if(id[i]&1)    {        puts("0");        return;    }    else id[i]/=2;    cnt=0;    dfs(1);    printf("%d\n",cnt);}int main(){    int T;    scanf("%d",&T);    while(T--) solve();    return 0;}


0 0
原创粉丝点击