1 | Chebyshev's Theorem |
2 | The Balance of the World |
3 | Identically Colored Panels Connection |
4 | And Then, How Many Are There? |
5 | Planning Rolling Blackouts |
6 | Watchdog Corporation |
7 | A Broken Door |
颓废了2,3天,比赛继续中。
4个小时过去了,除了我们组的“大神”出了3道以外,其他都是2道。题目太恶心了...
1.Chebyshev's Theorem(Prim)
教科书般的水题一道,基本上这道题的AC数就是今天参加比赛的队伍数了。重温了打素数表。
2.The Balance of the World
前后括号的匹配什么的,看AC数的话应该挺水吧。木有做
4.And Then, How Many Are There?
想破头的题。有<=24个盘子叠着放,盘子有颜色之分。每次只能从最上面提取2个颜色一样的盘子。起先以为只要模拟一下就好。后来发现牵扯到最优解什么的。有不同的取法会影响最后的结果。抛开最优解不说,光是模拟就让我无措。间的的想法就是建立一个结构,可以记录很多个父节点,子节点。然后把盘子间的覆盖关系映射成父子关系即可。然后慢慢遍历。实现过程中遇到各种各样的麻烦。还是平时练习太少了。
神一样的代码,完全没有知觉了(反正关于位dp什么的,日语解释的啊,坑爹):
#include <iostream>
#include <cstring>
using namespace std;
int n;
int x[24],y[24],c[24],r[24];
char memo[1<<24];
int hit(int i,int j) //判断两个盘子是否重叠
{
int L = r[i]*r[i] + r[j]*r[j] + 2 * r[i] * r[j];
int X = (x[i]-x[j])*(x[i]-x[j]);
int Y = (y[i]-y[j])*(y[i]-y[j]);
return X + Y < L;
}
int nocover(int n,int bit)
{
for(int i = 0 ; i < n ; i++)
{
if( (bit>>i&1) && hit(i,n) ) return false;
}
return true;
}
int dfs(int bit)
{
if(~memo[bit]) return memo[bit];
int ans = 0;
for(int i = 0 ; i < n ; i++)
{
for(int j = i+1 ; j < n ; j++)
{
if( (bit >> j & 1) && (bit >> i & 1) && c[i] == c[j] && nocover(i,bit) && nocover(j,bit) )
{
ans = max(ans , dfs( bit & ~(1<<j) & ~(1<<i) ) + 2);
}
}
}
return memo[bit] = ans;
}
int main()
{
while(cin >> n , n)
{
for(int i = 0 ; i < n ; i++)
{
cin >> x[i] >> y[i] >> r[i] >> c[i];
}
memset(memo,-1,sizeof(memo));
cout << dfs((1<<n)-1) << endl;
}
}
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <deque>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define REP(i,n) for((i)=0;(i)<(int)(n);(i)++)
#define foreach(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
int N;
int x[30],y[30],r[30],c[30];
bool graph[30][30];
bool used[(1<<24)];
void dfs(int mask){
int i,j;
if(used[mask]) return;
used[mask] = true;
vector <int> v;
REP(i,N) if(mask&(1<<i)){
bool bad = false;
REP(j,i) if(mask&(1<<j)) if(graph[j][i]) bad = true;
if(!bad) v.push_back(i);
}
REP(i,v.size()) REP(j,i){
int a = v[i], b = v[j];
if(c[a] == c[b]) dfs(mask ^ (1<<a) ^ (1<<b));
}
}
int main(void){
int i,j;
while(cin >> N){
if(N == 0) break;
REP(i,N) cin >> x[i] >> y[i] >> r[i] >> c[i];
REP(i,N) REP(j,N){
graph[i][j] = false;
if(i < j){
int dx = x[i] - x[j], dy = y[i] - y[j], d = dx*dx + dy*dy;
int rsum = r[i] + r[j];
if(d < rsum * rsum) graph[i][j] = true;
}
}
REP(i,(1<<N)) used[i] = false;
dfs((1<<N)-1);
int ans = 0;
REP(i,(1<<N)) if(used[i]){
int tmp = N - __builtin_popcount(i);
ans = max(ans,tmp);
}
cout << ans << endl;
}
return 0;
}
7. A Broken Door
这题貌似很多队伍在理解题意上花了很大的功夫,其实就是个迷宫,然后让你最小步数里完成。还有一个条件是,有一个门会是不通的。但你提前不知道是哪个门。大家都误解为提前知道最坏情况下的门,然后选择最短路劲。其实应该是选定一条线路,之后不管怎么出现坏门,都能在一个步数下完成。这个步数最小的情况就是最后的结果。说来说去还是没有说清楚...恩...还是不费脑力了,先效仿他人代码~
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>
using namespace std;
#define REP(i,n) for((i)=0;(i)<(int)(n);(i)++)
#define foreach(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
#define INF (1<<29)
int dx[]={1,-1,0,0},dy[]={0,0,1,-1};
int N;
vector <int> edge[910];
bool bad[40][40][4];
int score[910];
queue <int> q;
int baddist[910];
int dist[910];
void bfs(int a, int b){ // a-b disconnected
int i;
REP(i,N) baddist[i] = INF;
q.push(N-1); baddist[N-1] = 0;
while(!q.empty()){
int x = q.front(); q.pop();
REP(i,edge[x].size()){
int y = edge[x][i];
if(a == x && b == y) continue;
if(a == y && b == x) continue;
if(baddist[y] == INF){
baddist[y] = baddist[x] + 1;
q.push(y);
}
}
}
}
bool check(int D){
int i;
REP(i,N) dist[i] = INF;
q.push(0); dist[0] = 0;
while(!q.empty()){
int x = q.front(); q.pop();
int d = dist[x];
REP(i,edge[x].size()){
int y = edge[x][i];
if(dist[y] == INF && score[y] + d + 1 <= D){
dist[y] = d + 1;
q.push(y);
}
}
}
return (dist[N-1] != INF);
}
int func(void){
int i,j;
REP(i,N){
bfs(-1,-1);
score[i] = baddist[i];
REP(j,edge[i].size()){
bfs(i,edge[i][j]);
score[i] = max(score[i],baddist[i]);
}
}
int high = 2000, low = 0;
while(high-low > 1){
int mid = (high + low) / 2;
if(check(mid)) high = mid; else low = mid;
}
if(high == 2000) return -1;
return high;
}
int main(void){
int X,Y,i,j,k,tmp;
while(cin >> X >> Y){
if(X == 0 && Y == 0) break;
REP(i,X) REP(j,Y) REP(k,4) bad[i][j][k] = false;
REP(i,2*X-1){
if(i%2 == 0){
REP(j,Y-1){
cin >> tmp;
if(tmp == 1) bad[i/2][j][2] = bad[i/2][j+1][3] = true;
}
} else {
REP(j,Y){
cin >> tmp;
if(tmp == 1) bad[i/2][j][0] = bad[i/2+1][j][1] = true;
}
}
}
N = X * Y;
REP(i,N) edge[i].clear();
REP(i,X) REP(j,Y){
int st = i * Y + j;
REP(k,4) if(!bad[i][j][k]){
int i2 = i + dx[k], j2 = j + dy[k];
if(i2 >= 0 && i2 < X & j2 >= 0 && j2 < Y){
int st2 = i2 * Y + j2;
edge[st].push_back(st2);
}
}
}
int ans = func();
cout << ans << endl;
}
return 0;
}
发现现在的水平根本没法总结这些神一样的题目。还是写写算法总结什么的吧...诶...各种悲惨...
代码出处:http://www.graco.c.u-tokyo.ac.jp/icpc-challenge/index.php?2011%2F%C6%FC%C4%F8%C9%BD%2F06-27