2011暑假集训组队赛4

ID Title
1Chebyshev's Theorem
2The Balance of the World
3Identically Colored Panels Connection
4And Then, How Many Are There?
5Planning Rolling Blackouts
6Watchdog Corporation
7A 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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值