您的位置:首页 > 编程语言 > Qt开发

USTC Monthly Contest 2011-03-06

2011-03-08 18:46 211 查看
链接: http://acm.ustc.edu.cn/ustcoj/contest.php?contest=10

 

A题:图论题,将剩余的空位置看成一个节点,任何相邻的两点(都没有被占)建立一条无向边,问题可以转化为 一般图的最大匹配了,可以采用带花树算法实现求解。这里提供武汉大学 momodi 大牛的一个手写模板

 

一般图的最大匹配之带花树算法

 

//author: momodi@whuacm
struct Graph {
int n, match[maxn];
bool adj[maxn][maxn];
void clear() {
memset(adj, 0, sizeof(adj));
n = 0;
}
void insert(const int &u, const int &v) {
get_max(n, max(u, v) + 1);
adj[u][v] = adj[v][u] = 1;
}
int max_match() {
memset(match, -1, sizeof(match));
int ans = 0;
for (int i = 0; i < n; ++i) {
if (match[i] == -1) {
ans += bfs(i);
}
}
return ans;
}
int Q[maxn], pre[maxn], base[maxn];
bool hash[maxn];
bool in_blossom[maxn];
int bfs(int p) {
memset(pre, -1, sizeof(pre));
memset(hash, 0, sizeof(hash));
for (int i = 0; i < n; ++i) {
base[i] = i;
}
Q[0] = p;
hash[p] = 1;
for (int s = 0, t = 1; s < t; ++s) {
int u = Q[s];
for (int v = 0; v < n; ++v) {
if (adj[u][v] && base[u] != base[v] && v != match[u]) {
if (v == p || (match[v] != -1 && pre[match[v]] != -1)) {
int b = contract(u, v);
for (int i = 0; i < n; ++i) {
if (in_blossom[base[i]]) {
base[i] = b;
if (hash[i] == 0) {
hash[i] = 1;
Q[t++] = i;
}
}
}
} else if (pre[v] == -1) {
pre[v] = u;
if (match[v] == -1) {
argument(v);
return 1;
} else {
Q[t++] = match[v];
hash[match[v]] = 1;
}
}
}
}
}
return 0;
}
void argument(int u) {
while (u != -1) {
int v = pre[u];
int k = match[v];
match[u] = v;
match[v] = u;
u = k;
}
}
void change_blossom(int b, int u) {
while (base[u] != b) {
int v = match[u];
in_blossom[base[v]] = in_blossom[base[u]] = true;
u = pre[v];
if (base[u] != b) {
pre[u] = v;
}
}
}
int contract(int u, int v) {
memset(in_blossom, 0, sizeof(in_blossom));
int b = find_base(base[u], base[v]);
change_blossom(b, u);
change_blossom(b, v);
if (base[u] != b) {
pre[u] = v;
}
if (base[v] != b) {
pre[v] = u;
}
return b;
}
int find_base(int u, int v) {
bool in_path[maxn] = {};
while (true) {
in_path[u] = true;
if (match[u] == -1) {
break;
}
u = base[pre[match[u]]];
}
while (!in_path[v]) {
v = base[pre[match[v]]];
}
return v;
}
};
 

 

B题:数学题,题意大致是,给定三个数 m、a、b,求出这样的两个数 w 和 h,满足 w * h <= m,a / b <= w / h <= 1,而且保证让w 和 h的乘积最大,可以采用先建立素数表,枚举w,二分 h

 

#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 100000;
long long prime[10000];
bool tag[maxn];
int tot = 0;
void init()
{
memset(tag, 0, sizeof(tag));
prime[tot++] = 2LL;
for(int i = 3; i < maxn; i += 2) {
if( !tag[i] ) {
prime[tot++] = (long long)i;
for(int j = i + i; j < maxn; j += i) {
tag[j] = 1;
}
}
}
//printf("tot = %d/n", tot);
}
long long m, a, b;
int main()
{
init();
while( scanf("%lld %lld %lld", &m, &a, &b) == 3 && (m + a + b) ) {
long long w = -1, h = -1, l, r, mid;
for(int i = 0; i < tot; ++i) {
if( prime[i] * prime[i] > m) break;

l = i, r = tot - 1;
while(l <= r) {
mid = (l + r) >> 1;
if(prime[i] * prime[mid] > m ) { r = mid - 1; continue; }
if( b * prime[i] < a * prime[mid] ) { r = mid - 1; continue; }
if(w == -1 || w * h < prime[i] * prime[mid]) { w = prime[i]; h = prime[mid]; }
l = mid + 1;
}
}
printf("%lld %lld/n", w, h);
}
return 0;
}
 

 

C题:尚未解出

 

D题:模拟题,高精度加法

 

import java.math.BigInteger;
import java.util.Scanner;
import javax.naming.BinaryRefAddr;

public class Main {
public static void main(String[] args)
{
Scanner cin = new Scanner(System.in);
BigInteger a = new BigInteger("0");
BigInteger b = new BigInteger("0");
while (cin.hasNext())
{
a = cin.nextBigInteger();
b = cin.nextBigInteger();
System.out.println(a.add(b).toString());
}
}
}
 

 

E题:尚未解出

 

F题:尚未解出

 

G题:网络流,一开始想到了最大流,但是看到点那么多,以为会超时,没写。建立 N + 5 * N + C + 2 个节点,其中,N 表示 学生,5 * N 表示 N 个人的时间(5天),C 表示课程, 2 表示源点和汇点,把握好对应的边权,需要手写建立 hash 函数,或者直接调用 map

 

#include<stdio.h>
#include<string.h>
#include<queue>
#include<string>
#include<vector>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxV = 6000;
const int maxE = 3000000;
const int inf = 0x7fffffff;
struct node
{
int v, idx, w;
node *nxt;
};
node *G[maxV];
node E[maxE]; int nE = 0;
void init()
{
memset(G, 0, sizeof(G));
nE = 0;
}
void add(int u, int v, int w)
{
E[nE].v = v, E[nE].idx = nE, E[nE].w = w;
E[nE].nxt = G[u], G[u] = &E[nE++];
E[nE].v = u, E[nE].idx = nE, E[nE].w = 0;
E[nE].nxt = G[v], G[v] = &E[nE++];
}
int s, t; // source, sink
int h[maxV];
bool bfs()
{
memset(h, -1, sizeof(h));
//queue<int> q; q.push(s);
static int Q[maxV]; int Qs = 0, Qt = 0; Q[Qt++] = s;
h[s] = 0; int u;
while( Qs != Qt ) {
u = Q[Qs++]; if(Qs == maxV - 1) Qs = 0;
for(node *e = G[u]; e; e = e->nxt) {
if( (e->w) > 0 && h[e->v] == -1 ) {
h[e->v] = h[u] + 1;
Q[Qt++] = e->v;
if(Qt == maxV - 1) Qt = 0;
}
}
}
return h[t] != -1;
}
int dfs(int &curV, int curF)
{
if(curV == t) return curF;
int cntf = 0, tmpf;
for(node *e = G[curV]; e; e = e->nxt) {
if( (e->w > 0) && (h[e->v] == h[curV] + 1)
&& (cntf < curF) && ( (tmpf = dfs(e->v, min(e->w, curF - cntf))) > 0 ) ) {
e->w -= tmpf;
E[(e->idx) ^ 1].w += tmpf;
cntf += tmpf;
}
}
if(cntf == 0) h[curV] = -1;
return cntf;
}
int C, N;
struct info
{
int T, tot;
};
info A[1400];
map<string, int> LocA;
map<string, int> T, _T;
int K, X;
char cName[18], cTime[18];
char fName[700][18];
int fL[700];
bool tag[5];
int offset;
int  main()
{
T["Monday"] = 0, T["Tuesday"] = 1, T["Wednesday"] = 2, T["Thursday"] = 3, T["Friday"] = 4;
while( scanf("%d", &C) == 1) {
init();
LocA.clear(); _T.clear();
for(int i = 0; i < C; ++i) {
scanf("%s %s %d", cName, cTime, &A[i].tot);
A[i].T = T[ cTime ];
_T[ cName ] = A[i].T;
LocA[ cName ] = i;
}
scanf("%d", &N);
if(N == 0 && C == 0) break;
s = N + 5 * N + C, t = s + 1;

for(int i = 0; i < C; ++i) {
add(N + 5 * N + i, t, A[i].tot);
}
int ans = 0, sgn = 1, tmp;
for(int i = 0; i < N; ++i) {
scanf("%d %d", &K, &X);
if(X > 5 || K < X) sgn = 0;
ans += X;
if( sgn == 0 ) for(int j = 0; j < K; ++j) scanf("%s", cName);
else {
for(int j = 0; j < K; ++j) {
scanf("%s", fName[j]);
fL[j] = LocA[ fName[j] ];
}
//memset(tag, 0, sizeof(tag));
//for(int j = 0; j < K; ++j) tag[ A[ fL[j] ].T ] = 1;
//for(int j = 0; j < 5; ++j) if( tag[j] ) add(i, N + j, 1);
for(int j = 0; j < 5; ++j) add(i, N + 5 * i + j, 1);
for(int j = 0; j < K; ++j) add(N + 5 * i + A[ fL[j] ].T, N + 5 * N + fL[j], 1);
}
if( sgn ) add(s, i, X);
}
if( !sgn ) { puts("No."); continue; }
while( bfs() ) ans -= dfs(s, 0x7fffffff);
printf("%s/n", ans ? "No." : "Yes!");
}
return 0;
}
 

 

H题:矩阵 + 二分,这是一道很好的矩阵题目,关键在于如何建立矩阵,不妨先做做 POJ3233 题,那道题的一些结论对于求解该题有帮助。这题需要把握好细节。

 

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxN = 50;
typedef long long i64d;
i64d _M, _N, _P, K;

struct Matrix
{
i64d M[maxN][maxN];
};
void MUL(Matrix A, Matrix B, Matrix &C, i64d &X_X)
{
for(i64d i = 0; i < X_X; ++i) {
for(i64d j = 0; j < X_X; ++j) {
C.M[i][j] = 0;
for(i64d k = 0; k < X_X; ++k) {
if( !A.M[i][k] || !B.M[k][j] ) continue;
C.M[i][j] += (A.M[i][k] * B.M[k][j]) % _P;
C.M[i][j] %= _P;
}
}
}
}
void POWER(Matrix &x, i64d y, Matrix &E, i64d &X_X) {
if(y == 1LL || y == 0) return ;
POWER(x, y >> (0x1), E, X_X);
MUL(x, x, x, X_X);
if( y & (0x1) ) MUL(x, E, x, X_X);
}
i64d B[20], C[20];
i64d SUM(i64d X) {
if( X <= K ) {
i64d ans = 0;
for(i64d i = 0; i < X; ++i) {
ans += B[i]; // need not to add "% _P"
ans %= _P;
}
return ans;
}
i64d ans = 0;
for(i64d i = 0; i < K; ++i) {
ans += B[i]; // need not to add "% _P"
ans %= _P;
}
//printf("ans = %lld/n", ans);
Matrix E;
memset(E.M, 0, sizeof(E.M));
for(i64d i = 0; i < K; ++i) {
for(i64d j = 0; j < K; ++j) {
if(i == 0) E.M[i][j] = C[j];

if(i == j + 1LL) E.M[i][j] = 1LL;

if(i == j) {
E.M[i + K][j + K] = 1LL;
E.M[i][j + K] = 1LL;
}
}
}
Matrix x = E; i64d X_X = 2LL * K;
POWER(x, X - K + 1LL, E, X_X);
for(i64d i = 0; i < K; ++i) {
x.M[i][i + K] -= 1LL;
}
for(i64d j = 0; j < K; ++j) {
ans += (x.M[0][j + K] * B[K - j - 1]) % _P;
ans %= _P;
}
return ans;
}
int main()
{
while( scanf("%lld", &K) == 1 ) {
for(i64d i = 0; i < K; ++i) scanf("%lld", B + i);
for(i64d i = 0; i < K; ++i) scanf("%lld", C + i);
scanf("%lld %lld %lld", &_M, &_N, &_P);
for(i64d i = 0; i < K; ++i) B[i] %= _P, C[i] %= _P;
i64d ans_M = SUM( _M - 1LL ), ans_N = SUM( _N );
//printf("ans_M = %lld, ans_N =  %lld/n", ans_M, ans_N);
printf("%lld/n", ((ans_N - ans_M) % _P + _P) % _P);
}
return 0;
}
 

 

2011-03-08 by hzwu.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  matrix qt path c 算法 insert