The 2007 ACM Asia Programming Contest Changchun Site Internet Preliminary Contest
那天下午参加的比赛........
解题报告:
| A | 2450 | Is it possible? |
贴个代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int n;
char buf[10000];
char store[100][10000];
int sLen = 0;
int m[21], p[21], W[21], L[21], D[21];
int tm, tp, td;
bool dfs(int ind, int win, int draw, int lose)
{
if(draw > td * 2 || win * 3 + draw > tp) //当前平局数/分数不大于总平/总分,
return false;
if(ind >= n) //dfs到底,判断是否符合
{
if(draw != td + td || win != lose) //总的平局数符合,而且,胜负局数相等
return false;
for(int j = 0; j < n; j++)
{
if(W[j] > lose - L[j]) return false; //每队胜场不超过所有队的输场减去自己的输场
if(L[j] > win - W[j]) return false; //每队输场不超过所有队的胜场减去自己的胜场
if(D[j] + D[j] > draw) return false; //每队平场不超过所有队的平场的一半
}
return true;
}
int i;
for(i = 0; i * 3 <= p[ind] && i <= m[ind]; i++)
{
int d = p[ind] - 3 * i;
W[ind] = i;
D[ind] = d;
L[ind] = m[ind] - W[ind] - D[ind];
if(D[ind] < 0 || L[ind] < 0) //这个if其实可以不要
continue;
if(dfs(ind + 1, win + i, draw + d, lose + L[ind]))
return true;
}
return false;
}
int main()
{
while(scanf("%d", &n) == 1)
{
getchar();
int i;
tm = tp = 0;
sLen = 0;
for(i = 0; i < n; i++)
{
gets(buf);
char *token = NULL, *str = buf;
while( (token = strtok(str, " ")) != NULL)
{
str = NULL;
strcpy(store[sLen], token);
sLen++;
}
m[i] = atoi(store[sLen - 2]);
p[i] = atoi(store[sLen - 1]);
tm += m[i];
tp += p[i];
}
td = tm / 2 * 3 - tp; //td:总平局数
bool flag = true;
if(tm & 1) //各队场数和一定是偶数,一场比赛贡献度为2
flag = false;
else if(td < 0) //总平局数不为负
flag = false;
else if(tm > tp) //实际总分要大于总场数*2,一场比赛至少贡献2分
flag = false;
for(i = 0; i < n; i++)
{
if(p[i] > 3 * m[i] || p[i] == 3 * m[i] - 1) //对于每个队,他的分数不超过3*n,而且不为3*n-1,平一场为3*n-2
{
flag = false;
break;
}
}
if(!flag)
printf("Not possible\n");
else
{
if(!dfs(0, 0, 0, 0)) //dfs(队伍编号,总胜场数,总平,总输)
printf("Not possible\n");
else
printf("Possible\n");
}
}
return 0;
}
还有一题是
| G | 2456 | Stampeding |
动态规划题目,x[i]表示第i个时间段的任务数,cost(i,j)为i个进程j个任务时惊醒进程的系统耗费,dp[i][j]表示第i+1个时间段开始前进程数为j的最小耗费。
状态转移为:
dp[i][x[i]]=dp[i-1][j]+cost(x[i],x[i])
当i>x[i]时dp[i][j]=min( dp[i-1][j]+cost(j,x[i-1]) , dp[i][j-1]+Y )
当i<x[i]时dp[i][j]=dp[i][x[i]]
| H | 2457 | Sailboat |
是过的人最多的,但是我们的可能是因为先算后加的原因(人家过的似乎用的是先加后算的),有点可惜了...后来发现是中间有个小地方除错东西了...
还有一题
| E | 2454 | Hyper-Calculator |
对于对于"**"运算不知道该怎么处理,要是把准确值算出来,那么,如果后面是一个!的话,很可能超时,想到一种不超时的,可是需要知道底数的循环节或者对于10^40的循环节,也不好办阿...(怎么办阿?知道的牛提示下,谢谢!^_^)
解题报告:让人汗死.............
这个题目就是一个大数计算器,没有太多复杂的东西。题目里面对运算符的结合性没有明确说明,不过惯例都是左结合的。主要注意以下几点:计算指数要用二分法,不能直接算;计算阶乘时,大于200的阶乘模10^40都是0。有人提问,是先计算最终结果再求模,还是每次计算都求模,我无法回答他。按照题意当然是最终求模,但计算者可以简化为每一步求模。
不过注意,这个题目的主要陷阱就在此处,举个例子,0!=1;而 (10**40)! = 0;
另外,赛后上网查了一下,原来
| B | 2451 | Fatmouse and JavaBean |
这就是一个最短路径问题。分别求出老鼠、猫到各房间的最短时间即可。可用单源最短路的dijkstra算法或其他算法。
这一题,zju上面有过前面半部分的题目,还有I,II,III这3中题型,本题是II的一个延伸,在II的基础上,判断最短路,且最多豆的路径的条数,如果多于1,就是hard to say,否则,搜猫点到最短路的最前面那个
| C | 2452 | Transportation Power Augmentation |
这是一个约束最大流(constrained maximum flow)问题,其解法类似于最小费用流。注意本题边的耗费是分段线性函数(convex function)。出题者给出了最坏复杂度O(min{d, mu} m log n)的算法,其核心为含负权图上的successive shortest path(SSP)算法。
| D | 2453 | Candy |
每颗糖对应每个人只有两种状态,故可将糖表示为2^M种状态,可转换为网络流求解,每种糖对应一个顶点,每个人对应一个顶点,另建立源点汇点,人到汇点的路容量为floor(Bi/2),源点到每种糖的路容量为无穷,每种糖与每个人之间的喜好度为2则该种糖的个数为1,否则为0,直接求最大流ans,判断 (ans+N)与(B1+B2+..+BM)大小。
| F | 2455 | Credit hour |
50门课程的搜索。算法分为两步:
1.确定最小可行学分: 在[C, 2*C)范围内二分枚举学分值,DFS验证。DFS验证时亦可同时缩小当前二分上限。
2.找出字典序最小的解:可以证明只要选中的选修课字典序最小,总的课程字典序也最小。
这个出题者的数据量很大,没有很好的搜索优化就要超时。
浙公网安备 33010602011771号