剪刀石头布

Problem Description
现有M
个人一起玩剪刀石头布,以1
-M
编号,每人出一种,出过不再改变,但是我们并不知道它到底是哪一种。 
(其中石头赢剪刀,剪刀赢布,布赢石
头,一样则平)
裁判用两种说法对这M
个人所构成的输赢关系进行描述: 
一:"1 A B",表示第A个人和第B个人出的一样。 
二:"2 A B",表示第A个人赢第B个人。 
裁判对M个人,用以上两种说法,连说N句话,其中有真的、也有假的。

一句话出现以下情况,就是假话,否则就是真话。 

1该句话与之前的某些真话冲突; 

2)该句话中A或B比M大; 
3)该句话表示A赢A。 
请根据给定的M和N,输出假话数。其中(1<= M<=10,000),(0<= N <= 10,000)

Input
第1行是一个自然数K,代表有K组数据。
每组数据以一个空行分隔,其中每组数据的第1行是两个自然数M、N,以空格分开。 
每组数据的第2行至N+1行,每行是三个自然数X,A,B,三个数之间用空格分开,X(1或2)表示说法的种类。
 
Output

每组数据对应一行,每行有一个整数,代表假话数。

sample input

3

43 11

1 4 3

2 3 3

1 4 1

1 4 4

2 3 3

1 2 2

2 1 4

1 1 1

2 1 4

2 3 4

2 3 2


66  9

2 3 1

2 4 4

2 1 2

2 4 3

2 4 2

2 2 3

1 3 2

1 2 1

1  1 1


6 7

2 3 7

2 1 2

2 4 4

1 2 1

1 3 2

1 2 3

2 1 3


sample output

4

3

建一个图,如果A win B, 则A 到 B的边权为1, 而B到A的边权为2;如果A draw B, 则A 到 B的边权为0, B到A的边权为0。 每次输入一句话则搜索两者是否边连通,如果不连通则加边;如果连通,则看两者的距离MOD 3的值, 如果MOD 3 得1则前者胜后者,得0则平,得2 则后者胜前者。比如说A胜B, B 胜 C, 则可知C胜A,那么A->B = 1, B->A = 2, B->C = 1, C->B = 2,那么可推出A->C = 2:A->B + B->C = 2 , 或者C->A = C->B + B->A = 4 mod 3 =1;同者都说明C win A。


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#include<string>
using namespace std;
struct Edge
{
	int v, next, f;
}e[20000];
int g[20000];
int num;
void addedge(int a, int b, int f)
{
	e[++num].v = b;
	e[num].next = g[a];
	e[num].f = f;
	g[a] = num;
}
int vis[10000];
int dfs(int a, int b)
{
	int i, ret  = 0;;
	for(i = g[a]; i; i = e[i].next)
	{
		int v = e[i].v;
		if(v == b)
			return e[i].f;
		if(vis[v])
		{
			vis[i] = 0;
			ret = dfs(v, b);
			vis[a] = 1;
		}
		if(ret >= 0)return e[i].f + ret;
	}
	return -1;
}
int main()
{
	int n, m;
	int i, j, k;
	int cnt;
	int t;
	int a, b, q;
	scanf("%d", &t);
	while(t--)
	{
		int bf = 0;
		cnt = 0;
		int flag = 0;
		scanf("%d%d", &m, &n);
		num = 0;
		for(int i = 0; i <= 2 * n; i++)e[i].f = -1;
		memset(g, 0, sizeof(g));
		memset(vis, 1, sizeof(vis));
		while(n--)
		{
			scanf("%d%d%d", &q, &a, &b);
			if(q == 1)
			{
				if(a == b)continue;
				vis[a] = 0;
				int dis = dfs(a, b);
				vis[a] = 1;
				if(dis == -1)
				{
					addedge(a, b, 0);
					addedge(b, a, 0);
				}
				else if(dis % 3 != 0)
					cnt ++;
			}
			if(q == 2)
			{
				if(a == b || a > m || b > m)
				{
					cnt ++;
					continue;
				}
				vis[a] = 0;
				int dis = dfs(a, b) % 3;
				vis[a] = 1;
				if(dis != -1 && dis != 1)cnt ++;
				if(dis == -1)
				{
					addedge(a, b, 1);
					addedge(b, a, 2);
				}
			}
		}
		printf("%d\n", cnt);
	}
    return 0;
}



评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值