Friends

首先这道题刚开始我就理解错题意了。再细读一边,they can choose to become online friends (communicating using online applications) or offline friends (mostly using face-to-face communication).由become online friends可知,说明在线和离线是一对朋友之间的边的状态。这道题的题意就是问有几种方案可以使得每个人的在线边和离线边的边数都相同。而且最多有8个人。

很显然的是,如果某个点的度数是奇数,那么显然不存在方案。

下意识地求一下复杂度,发现8的人的话,所能构成的无向简单图的边数最多是(8*7)/2=28条边。这时候就要往暴力搜索方面考虑,最多是2^28种可能,因为一条线无非是online和offline两种状态,对边一一枚举进行dfs。但此时我的代码能力还是极差的,就不知道该怎么写。

然后参考了题解,发现我没有想到的就是我连dfs的终止条件都不知道该怎么判断。那么题解的方法就是,如果这条线是online的,那么连接这条线的两个点就有两种属性,一种属性就是这个点连接的online的边数有几条,另一种属性是这个点offline的边数有几条(在代码中我用on【i】,off【i】来表示)。这时候我就考虑从边开始dfs了,当这条边要online的时候,此时与这条边相连的两点的on【】都要加一。在最后,当枚举到m+1时,说明此时要return了,那么我就要判断,对每一个点来说,是不是全部满足on【i】==off【i】如果全部满足,那么就可以ans+1,这种情况是可行的。同理,恢复on,off值后在进行offline的dfs。

但是事实上,仅是这样复杂度还是太高,肯定会tle。

这样就要在dfs中进行优化,可以发现,当on【i】小于这个点度数的一半的时候,肯定是可以dfs的,但是一旦大于,那么之后的枚举无疑是浪费时间。

所以我们此时就要在中间加一段这样的判断。

这个地方我开始写的时候想错了,写成了<=.事实上后边还有一段要进行加1操作,所以不能是等于。

感受:这道题比较拓展的地方就是对剪枝,和搜索中结束条件的使用的灵活处理,思维要变化,不能局限,这道题没有什么难度,但是对我来说想出这个解决办法还是需要多做题的。

具体代码如下:

#include<bits/stdc++.h>
using namespace std;
int bian[30][3];
int du[10];
int on[30],off[30];
int ans;
int t,n,m;
int a,b;

void dfs(int s)
{
    if(s==m+1)
    {
        int logal=0;
        for(int i=1;i<=n;i++)
        {
            ///cout<<"i:"<<i<<"  on[]: "<<on[i]<<"  off[]: "<<off[i]<<endl;
            if(on[i]!=off[i])
            {
                logal=1;
                break;
            }
        }
        if(logal==0)
            ans++;
        cout<<"&&&&"<<ans<<endl;
        return;
    }
    int point_a=bian[s][0];
    int point_b=bian[s][1];

    if(on[point_a]<du[point_a]/2 && on[point_b]<du[point_b]/2)
    {
        on[point_a]++;
        on[point_b]++;///此边所在的两点都变成了on状态
        dfs(s+1);
        on[point_a]--;
        on[point_b]--;
    }
    if(off[point_a]<=du[point_a]/2 && off[point_b]<du[point_b]/2 )
    {
        off[point_a]++;
        off[point_b]++;
        dfs(s+1);
        off[point_a]--;
        off[point_b]--;
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        memset(on,0,sizeof(on));
        memset(off,0,sizeof(off));
        memset(du,0,sizeof(du));
        ans=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            bian[i][0]=a;
            bian[i][1]=b;//bian记录了两端点
            du[a]++;
            du[b]++;
        }
        for(int i=1;i<=n;i++)
        {
            if(du[i]%2==1)
                ans=-1;
        }
        if(ans==-1)
            cout<<0<<endl;
        else
        {
            dfs(1);//按边进行dfs
            cout<<ans<<endl;
        }
    }
}

Problem Description

There are $n$ people and $m$ pairs of friends. For every pair of friends, they can choose to become online friends (communicating using online applications) or offline friends (mostly using face-to-face communication). However, everyone in these $n$ people wants to have the same number of online and offline friends (i.e. If one person has $x$ onine friends, he or she must have $x$ offline friends too, but different people can have different number of online or offline friends). Please determine how many ways there are to satisfy their requirements.

 

 

Input

The first line of the input is a single integer $T\ (T=100)$, indicating the number of testcases. For each testcase, the first line contains two integers $n\ (1 \le n \le 8)$ and $m\ (0 \le m \le \frac{n(n-1)}{2})$, indicating the number of people and the number of pairs of friends, respectively. Each of the next $m$ lines contains two numbers $x$ and $y$, which mean $x$ and $y$ are friends. It is guaranteed that $x \neq y$ and every friend relationship will appear at most once.

 

 

Output

For each testcase, print one number indicating the answer.

 

 

Sample Input

 

2 3 3 1 2 2 3 3 1 4 4 1 2 2 3 3 4 4 1

 

 

Sample Output

 

0 2

 

 

Author

XJZX

 

 

Source

2015 Multi-University Training Contest 2

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值