JOJ2701 Party

 

2701: Party

Result TIME Limit MEMORY Limit Run Times AC Times JUDGE
1s 8192K 116 23 Standard

Go, go, go, it's party time !!! A great many of guests are invited. Guests are numbered from 1 to N. To make the party more joyful, every 3 guests, who are friends to each other, or strangers to each other, will be asked to make a show together. For some preparation reasons, could you please tell me how many shows shall be performed?

Input

Each test case begins with two integers N, M (N <= 1000, M <= 10000). Then M lines follows, each of them will contain two integers a and b, telling that a and b are friends. None of the friend relations will appear more than once in each test case. The inputs terminates when N = M = 0.

Output

For each test case, print the number of shows to be performed in a single line.

Sample Input

3 1
1 2

3 3
1 2
2 3
1 3

5 3
1 2
2 3
1 3
0 0

Sample Output

0
1
4

 

Problem Source: homeboy

 

This problem is used for contest: 168 

 

由于对算法知识的匮乏,导致对题目分类并不是很擅长,估且把它放到组合数学里吧。

这是今年计算机10级新生赛(我竟然去参见了)的最后一道题,当时以为是图论题呢,因为对图论的陌生,所以就尝试着暴力来解,结果可想而知,无尽的TLE。

后来飞哥给我讲了这道题的解法,很简单的思路啊,不过要是没想到的话,真的没头绪。

言归正传...

 

思路:这道题直接来求的话不太好想出高效的算法,所以逆向来考虑,我们来求出不是3人都不认识或者都认识的情况(不妨称之为不完美组合)的数量res,然后用所有的可能情况减去res就得到了我们要的结果了。

 

具体算法:

设人数是n。

对于每一个人pi来说可能的不完美组合数是和pi是朋友的人数乘以和pi不是朋友的人数结果是resi。

我们假设有三个人A,B,C。

可能的情况(不完美组合情况)是(A+B,A-C,B-C),(A+B,A-C,B+C),(A+B,A+C,B-C)【注:其中+代表两者是朋友关系,-代表不是朋友关系】.

这样当我们按照上面一个一个求resi的时候,就会出现重复的现象。

对于第一种情况(A+B,A-C,B-C),我们再对A和B求resi时都会把(A,B,C)这种组合算成一种不完美组合。

对于第二种情况(A+B,A-C,B+C),我们再对A和C求resi时会把(A,B,C)这种组合算成一种不完美组合。

对于第三种情况(A+B,A+C,B-C),我们再对B和C求resi时会把(A,B,C)这种组合算成一种不完美组合。

当然ABC的不完美组合情况只能是三种情况的一种,但是无论哪种都是对每一种不完美组合都多算了一遍。

所以当我们得到res=res1+res2+res3+...+resi+...+resn之后要令res/=2.这样子就得到了所有不完美组合的情况数量。

然后用所有情况数C(n,3)-res就是最后结果了。

 

这里还有个问题就是怎么求组合数C(n,m).

当然有两个比较常用的方法

第一种:利用组合数的一个性质即C(n,m)=C(n-1,m)+C(n-1,m-1).递归求解。

第二种:利用组合数定义来C(n,m)=A(n,m)/(m!)来迭代求解。

对于第一种因为这道题说了人数是上限是1000,要是递归太多,加上测试数据多一些的话,一定TLE。

第二种的话的问题就好一些了。

C(n,m)=(n-m+1)/1*(n-m+2)/2*...(n-m+i)/i*...n/m.

这样迭代求就不会超时了。

另外说一下,两个方法都有一个通病,就是都不能算太大的数,所以应用范围有限,但是这个提目只需求C(n,3),所以一定不会超范围。

 

强调一下,一样的算法我用C就是0.19s,C++就是0.92,看来读入输出的影响不可忽略啊。

继续感谢飞哥的无私讲解。

Code:

<textarea cols="50" rows="15" name="code" class="cpp">/* *JackyZheng *2010/12/04 *C */ #include&lt;stdio.h&gt; #include&lt;string.h&gt; int a[1001]; int combine(int n,int m) { int t=1; for(int i=1;i&lt;=m;i++) { t*=(n-m+i); t/=i; } return t; } int main() { int n; int m; int temp1,temp2; int res; while(scanf("%d%d",&amp;n,&amp;m)) { res=0; if(n==0&amp;&amp;m==0) break; memset(a,0,sizeof(a)); for(int i=1;i&lt;=m;i++) { scanf("%d%d",&amp;temp1,&amp;temp2); a[temp1]++; a[temp2]++; } for(int i=1;i&lt;=n;i++) { res+=a[i]*(n-a[i]-1); } res/=2; printf("%d/n",combine(n,3)-res); } return 0; } </textarea> 

 

你可能感兴趣的:(c,算法,input,each,Go,output)