UVALive 4887 Soccer 状压+模拟

题目链接:点击打开链接

题意:n个球队,m场比赛

下面n行表示n个球队的名字。

下面m场比赛表示该场比赛的2个队得分。

-1表示我们可以任意填。

这种任意填的比赛场数不超过12场。

求:

胜一场球队得2分,平得1分,败得0分。

求每个球队最好名次与最差名字。

每场只有3个状态,最多只有12场,所以状压一下,3^12个状态。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <iostream>
using namespace std;
const int N = 20 + 2;

map<string, int> id;
vector<int> l, r;
char s[200], ss[200];

int n;
int base[N], tob[N], put[N], rank[N];
int mx[N], mi[N];
string name[N];

bool cmp(int x, int y) {
	return tob[x] > tob[y];
}

void upmx(int& z, int x) {
	if (z == -1)
		z = x;
	else if (z < x)
		z = x;
}

void upmi(int& z, int x) {
	if (z == -1)
		z = x;
	else if (z > x)
		z = x;
}

void dfs(int dep) {
	if (dep == l.size()) {
		for (int i = 1; i <= n; ++i) {
			rank[i] = i;
			tob[i] = base[i];
		}
		for (int i = 0; i < l.size(); ++i) {
			if (put[i] == 0) {
				++ tob[l[i]];
				++ tob[r[i]];
			} else if (put[i] == 1) {
				tob[l[i]] += 3;
			} else
				tob[r[i]] += 3;
		}
		sort(rank + 1, rank + 1 + n, cmp);
		int cur = 1;
		upmx(mx[rank[1]], 1);
		upmi(mi[rank[1]], 1);
		for (int i = 2; i <= n; ++i) {
			if (tob[rank[i]] != tob[rank[i - 1]])
				cur = i;
			upmx(mx[rank[i]], cur);
			upmi(mi[rank[i]], cur);
		}
	} else {
		put[dep] = 0;
		dfs(dep + 1);
		put[dep] = 1;
		dfs(dep + 1);
		put[dep] = 2;
		dfs(dep + 1);
	}
}

void pu(int x) {
	if (x == 1)
		printf("1st");
	else if (x == 2) {
		printf("2nd");
	} else if (x == 3) {
		printf("3rd");
	} else {
		printf("%dth", x);
	}
}

int main() {
	int m, a, b, x, y, len, cas = 0;
	while (~scanf("%d%d", &n, &m)) {
		if (0 == n && 0 == m)
			break;
		if (cas == 0)
			cas = 1;
		else
			puts("");
		id.clear();
		for (int i = 1; i <= n; ++i) {
			cin >> name[i];
			id[name[i]] = i;
		}

		memset(base, 0, sizeof base);
		l.clear();
		r.clear();
		while (m -- > 0) {
			scanf("%s vs %s %d %d", s, ss, &a, &b);
			len = strlen(ss);
			ss[--len] = '\0';
			x = id[s];
			y = id[ss];
			if (a == -1) {
				l.push_back(x);
				r.push_back(y);
			} else {
				if (a == b) {
					++ base[x];
					++ base[y];
				} else if (a > b)
					base[x] += 3;
				else if (b > a)
					base[y] += 3;
			}
		}

		memset(mx, -1, sizeof mx);
		memset(mi, -1, sizeof mi);
		dfs(0);
		for (int i = 1; i <= n; ++i) {
			printf("Team ");
			cout << name[i];
			printf(" can finish as high as ");
			pu(mi[i]);
			printf(" place and as low as ");
			pu(mx[i]);
			puts(" place.");
		}
	}
	return 0;
}
时间: 2024-08-04 14:38:37

UVALive 4887 Soccer 状压+模拟的相关文章

状压DP uvalive 6560

1 // 状压DP uvalive 6560 2 // 题意:相邻格子之间可以合并,合并后的格子的值是之前两个格子的乘积,没有合并的为0,求最大价值 3 // 思路: 4 // dp[i][j]:第i行j状态下的值 5 // j:0表示不合并,1表示向下合并 6 // 一开始输入要修改一下,然后滚动数组优化 7 8 #include <iostream> 9 #include <algorithm> 10 #include <cstring> 11 #include &

【11.8校内测试】【倒计时2天】【状压DP】【随机化?/暴力小模拟】

Solution 数据范围疯狂暗示状压,可是一开始发现状态特别难受. 将每一层的奇偶性状压,预处理所有状态的奇偶性.每一层的输入代表的其实可以是下一层某个点可以被从这一层哪些点转移到. 所以枚举每个状态,再枚举下一层转移到哪个点,统计这个点被这个状态更新的话正边和反边分别的奇偶性,转移即可. 第二层和最后一层单独处理即可. Code #include<bits/stdc++.h> #define mod 998244353 using namespace std; int x, dp[2][(

UVA 1412 - Fund Management(用vector容器模拟状态的状压dp)

Frank is a portfolio manager of a closed-end fund for Advanced Commercial Markets (ACM ). Fund collects money (cash) from individual investors for a certain period of time and invests cash into various securities in accordance with fund's investment

LA UVaLive 6625 Diagrams &amp; Tableaux (状压DP 或者 DFS暴力)

题意:给一个的格子图,有 n 行单元格,每行有a[i]个格子,要求往格子中填1~m的数字,要求每个数字大于等于左边的数字,大于上边的数字,问有多少种填充方法. 析:感觉像个DP,但是不会啊...就想暴力试试,反正数据量看起来不大才7,但是...TLE了,又换了一个暴力方法,2秒多过了,差点啊. 其实这是一个状压DP,dp[i][s]表示在第 i 列,在集合 s 中有方法数,那么怎么转移呢,这个还是挺简单的,就是判断第i+1列是不是比第 i 列都大于等于就ok了, 输入时先把行,转化成列,再计算,

[noip模拟]食物中毒&lt;暴搜+状压优化&gt;

问题描述 Bqc经过一段时间的研究发现,要解这种毒需要一种特殊的药物.不幸的是,这种药物在 市面上不存在,没有办法Bqc只好亲自制得这种药物.它含有M种化学物质A1,A2,…,AM.现 在Bqc的手上有N种药材(每种药材只有一种),每种药材含有若干种化学物质(Bqc他有一种 机器,只要将药材放入机器,就能制得相应的药物). Bqc需要你的帮助,他希望你能帮他选取若干种药材,用这些选取的药材制作出Bqc需要 的药物.由于这些化学物质是有毒的,因此你选出来的药物,必须含有这M种化学物质. 有一点需要

jzoj5990. 【北大2019冬令营模拟2019.1.6】Bear (状压dp)

题面 题解 我永远讨厌dp.jpg 搞了一个下午优化复杂度最后发现只要有一个小trick就可以A了→_→.全场都插头dp就我一个状压跑得贼慢-- 不难发现我们可以状压,对于每一行,用状态\(S\)表示有哪些格子是已经被上一行推倒了的,那么我们可以枚举本行所有格子的字母情况,然后计算一下这个时候下一行格子被推倒的情况,把这一行的贡献加到下一行就行了. 简单来说就是记一个\(f[pos][S]\)表示第\(pos\)行,格子被推倒的情况为\(S\)时的方案数,\(dp[pos][S]\)为所有方案中

HDU-4628 Pieces 状压DP

给出一行字符串,每次可以删去一个回文子串,子串可以是不连续的,因此用状压比较好模拟,求删掉整个字符串需要的最少步数. 字符串的最大长度为16,因此不能逐行枚举状态,首先预处理出来所有的的回文子串,然后从第一步开始,依次状压第i步能到达的状态,如果能达到母串,跳出. 还有初始化不要用图省事用memset..不优越的姿势+函数导致T了数发. #include <iostream> #include <cstdio> #include <cstring> #include &

UVa 11825 (状压DP) Hackers&#39; Crackdown

这是我做状压DP的第一道题,状压里面都是用位运算来完成的,只要耐下心来弄明白每次位运算的含义,还是容易理解的. 题意: 有编号为0~n-1的n台服务器,每台都运行着n中服务,每台服务器还和若干台其他服务器相连.对于每台服务器,你可以选择停止该台以及与这台服务器相连的服务器的一项服务.如果一台服务器的所有服务都被停止,则这台服务器瘫痪.问最多能使多少台服务器瘫痪 转化为数学模型(题目是如何抽象成这种数学模型的也要好好想想): 把n个集合尽可能多的分成若干组,使得每组所有集合的并集为全集.这里集合P

【POJ 2411】Mondriaan&#39;s Dream(状压dp)

[POJ 2411]Mondriaan's Dream(状压dp) Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 14107   Accepted: 8152 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in hi