srm527 T1 && T2

T1:

problem:

有n个节点,要求构造一棵树,第i个节点的权值为score[degree[i]],degree[i]是节点i的度数。整个树的权值为所有节点权值之和。问树的权值最大为多少。


solution:

显然节点标号是无所谓的,所以就树定向,父亲节点标号小于儿子节点。设fij代表前i - 1个节点处理完了,后面还有j个节点没有父亲。每次枚举当前节点有多少儿子即可转移。


#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

int f[100][100];

class P8XGraphBuilder {
public:
    int solve(vector <int> scores) {
	int n = scores.size() + 1;
	memset(f, -1, sizeof(f));
	f[1][n - 1] = 0;
	for (int i = 1; i <= n; ++i)
	    for (int j = 0; j <= n - i; ++j) 
		if (~f[i][j]) {
		    f[i + 1][j] = max(f[i + 1][j], f[i][j] + (i != 1 ? scores[0] : 0));
		    for (int k = 1; k <= j; ++k)
			f[i + 1][j - k] = max(f[i + 1][j - k], f[i][j] + scores[k - (i == 1)]);
		}
	return f[n + 1][0];
    }
};

T2:

problem:

给定一个带有'?','1','0'的大小为n * m 的矩阵, 再给 m 个长度为 n 的带有'0' '1' '?'的列('?'代表0,1都有可能)。现在要确定矩阵的所有问号,使得m个列的某种排列能和矩阵的所有列对应起来,输出字典序最小的方案。


solution:

如果不要求字典序最小的话,直接二分图匹配即可。要求字典序最小的话,则只要依次枚举每个问号,尝试放0,那么就会删除一些边。如果删完边还能匹配,那么就换成新图(该位置能放0),否则就保留原图(该位置必须放1)。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cassert>
using namespace std;

bool graph[33][33];
bool f[33][33], vis[33];
int my[33], mt[33];

bool find(int x, int n) {
    for (int i = 0; i < n; ++i)
	if (!vis[i] && f[x][i]) {
	    vis[i] = true;
	    if (my[i] == -1 || find(my[i], n)) {
			my[i] = x;
			return true;
	    }
	}
    return false;
}

bool check(int n) {
    memset(my, -1, sizeof(my));
    int ans = 0;
    for (int i = 0; i < n; ++i) {
	memset(vis, false, sizeof(vis));
	if (find(i, n)) ++ans;
    }
    if (ans == n) return true;
    return false;
}

class P8XMatrixRecovery {
public:
    vector <string> solve(vector <string> rows, vector <string> columns) {
	int R = rows.size(), C = rows[0].size();
	memset(graph, false, sizeof(graph));
	for (int i = 0; i < C; ++i)
	    for (int j = 0; j < C; ++j) {
			int k;
			for (k = 0; k < R; ++k)
			    if (rows[k][i] != columns[j][k] && 
				rows[k][i] != '?' && columns[j][k] != '?')
					break;
			if (k >= R) graph[i][j] = true;
	    }
	for (int x = 0; x < R; ++x)
	    for (int y = 0; y < C; ++y) 
		if (rows[x][y] == '?') {
		    memcpy(f, graph, sizeof(f));
		    memset(f[y], false, sizeof(f[y]));
		    for (int i = 0; i < C; ++i)
			if (graph[y][i] && columns[i][x] != '1')
			    f[y][i] = true;
		    if (check(C)) 
			memcpy(graph, f, sizeof(graph));  
		}
	memcpy(f, graph, sizeof(f));
	assert(check(C));
	for (int i = 0; i < C; ++i)
		mt[my[i]] = i;
	for (int i = 0; i < R; ++i)
	    for (int j = 0; j < C; ++j) 
		if (rows[i][j] == '?') {
		    if (columns[mt[j]][i] == '?')
			rows[i][j] = '0';
		    else rows[i][j] = columns[mt[j]][i];
		}
	return rows;
    }
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值