9度-九度OJ之我与名企有个约会趣味编程系列赛(1)

A.液晶屏裁剪

简单题。题目给出的长宽比例可能不是最简形式,所以首先化简,然后放大这个最小比例直到最大的比当前的长宽小于或等于。

#include <iostream> 
#include <cstring> 
#include <cstdio> 
#include <string> 
#include <queue> 
using namespace std; 
  
int gcd(int x,int y) 
{ 
    int n; 
    while(y) 
    { 
        n=x%y; 
        x=y; 
        y=n; 
    } 
    return x; 
} 
  
int main() 
{ 
    int a, b, c, d; 
    while(scanf("%d %d %d %d", &a, &b, &c, &d) != EOF){ 
        int x, y; 
        x = gcd(c, d); 
        c = c / x; 
        d = d / x; 
        x = a / c; 
        y = b / d; 
        x = x>y?y:x; 
  
        printf("%d %d\n", c * x, d * x); 
    } 
    return 0; 
} 

B.寻找最长合法括号序列

栈的应用,模拟题。首先得分析出,最长合法括号序列肯定是独立存在的,不存在两个最长合法括号序列重叠的情况,若重叠只能得到一个更长的序列。那么,我们需要一个辅助数组记录原序列当中哪些括号是被匹配过的,记1。然后再线扫这个辅助数组中最长连续的1的个数。

#include<iostream> 
#include<cstdio> 
#include<cmath> 
#include<cstring> 
#include<cstdlib> 
#include<iomanip> 
#include<string> 
#include<algorithm> 
#include<ctime> 
#include<stack> 
#include<queue> 
#include<vector> 
#define N 1000005 
using namespace std; 
char str[N],sub[N]; 
stack<int> s; 
int match(int a,int b) 
{ 
    if(str[a]=='('&&str[b]==')')  
        return 1; 
    return 0; 
} 
int main() 
{ 
    int len,i,j,l,start,end; 
    while(cin>>len>>str) {   
        memset(sub,0,sizeof(sub)); 
        s.push(0); 
        for(i=1;i<len;i++)  { 
            if(s.empty()) s.push(i); 
            else if(match(s.top(),i)){ 
                sub[s.top()]=1; 
                sub[i]=1; 
                s.pop(); 
            } 
            else 
                s.push(i);                   
        } 
        i=start=end=l=0; 
        int num = 0; 
        while(i<len){ 
            j=0; 
            while(i<len&&sub[i]==0)  
                i++;j=i; 
            while(i<len&&sub[i])  
                i++; 
            if(i-j>l){ 
                l=i-j; 
                start=j; 
                end=i; 
                num=1; 
            } 
            else if(i-j==l){ 
                num++; 
            } 
        } 
  
        printf("%d %d\n",end-start, num); 
    } 
    return 0; 
} 

C.角斗士

状态压缩DP。初看规模,n只有18,马上想到是dfs搜索或者是状态压缩dp。介于dp本人不是很强,比赛中没想出去,赛后看了一些别人的思路。

令数组dp[x]表示x在二进制上为1那些人活着的概率,比如现在只有3个人,那么dp[5]表示第一个人和第三个人活着的概率。由于比赛是随即选择两个人,那么每场比赛的概率为1 / C(活着的人的个数,2)。最终的概率应该是叠加上去。

那么状态转移方程为dp[i ^ (1 << j)] += dp[i] * win[j][k] / pos。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
using namespace std;

double pos[1 << 18];
double win[18][18];

int Cout1Num(int n)
{
	int x = 0;
	while(n){
		x++;
		n = n & (n - 1);
	}
	return x;
}

int main() 
{
	int n;
	while (scanf("%d", &n) != EOF) {
		int i, j, k;
		for (i = 0; i < n; ++i) {
			for (j = 0; j < n; ++j) {
				scanf("%lf", &win[i][j]);
			}
		}
		memset(pos, 0, sizeof(pos));
		pos[(1 << n) - 1] = 1.0;

		for (k = (1 << n) - 1; k > 0; --k) {
			int c = Cout1Num(k);
			int sum = c * (c - 1) / 2;

			if (c == 1) {
				continue;
			}

			for (i = 0; i < n; ++i) {
				if ((k & (1 << i)) == 0) {
					continue;
				}
				for (j = i + 1; j < n; ++j) {
					if ((k & (1 << j)) == 0) {
						continue;
					}
					pos[k ^ (1 << j)] += pos[k] * win[i][j] / sum;
					pos[k ^ (1 << i)] += pos[k] * win[j][i] / sum;
				}
			}
		}

		for (i = 0; i < n; ++i) {
			if(i)
				printf(" ");
			printf("%lf", pos[1 << i]);
		}
		printf("\n");
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值