期末复习之枚举

期末复习之枚举

1.Communication System

描述
We have received an order from Pizoor Communications Inc. for a special communication system. The system consists of several devices. For each device, we are free to choose from several manufacturers. Same devices from two manufacturers differ in their maximum bandwidths and prices.
By overall bandwidth (B) we mean the minimum of the bandwidths of the chosen devices in the communication system and the total price § is the sum of the prices of all chosen devices. Our goal is to choose a manufacturer for each device to maximize B/P.
输入
The first line of the input file contains a single integer t (1 ≤ t ≤ 10), the number of test cases, followed by the input data for each test case. Each test case starts with a line containing a single integer n (1 ≤ n ≤ 100), the number of devices in the communication system, followed by n lines in the following format: the i-th line (1 ≤ i ≤ n) starts with mi (1 ≤ mi ≤ 100), the number of manufacturers for the i-th device, followed by mi pairs of positive integers in the same line, each indicating the bandwidth and the price of the device respectively, corresponding to a manufacturer.
输出
Your program should produce a single line for each test case containing a single number which is the maximum possible B/P for the test case. Round the numbers in the output to 3 digits after decimal point.
样例输入
1 3
3 100 25 150 35 80 25
2 120 80 155 40
2 100 100 120 110
样例输出
0.649

思路:以每个带宽为下限,对每一个设备求最小价格。如果该设备带宽全小于设置下限,该下限不成立,return。把这些价格加起来得到当前状态总价格,取不同下限情况中的最大B/P。
下面这个AC

#include<bits/stdc++.h>
using namespace std;
int n,T;
int B[105][105],P[105][105],m[105];
double ans;
void calc(int limit)
{
	double sumP=0;
	for (int i=1; i<=n; ++i){
		double mn=1e8;
		for (int j=1; j<=m[i]; ++j)
			if (B[i][j]>=limit) mn=min(mn,1.0*P[i][j]);
		if (mn==1e8) return;
		sumP+=mn;
	}
	ans=max(ans,1.0*limit/sumP);
}
int main()
{
	scanf("%d",&T);
	while (T--){
		ans=0;
		scanf("%d",&n);
		for (int i=1; i<=n; ++i){
			scanf("%d",&m[i]);
			for (int j=1; j<=m[i]; ++j)
			  scanf("%d%d",&B[i][j],&P[i][j]);
		}
		for (int i=1; i<=n; ++i)
			for (int j=1; j<=m[i]; ++j)
				calc(B[i][j]);
		printf("%.3lf\n",ans);
	}
	
}

这个WA
但我认为是一样的,存疑

#include <iostream>
#include <set>
#include <string>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <string.h>
#include <queue>
#include <limits.h>
#include <iomanip>
using namespace std;
int T, n;
int m[110] = {};
double imax = 0;
struct BP{
    int b, p;
}bp[105][105] = {};
void solve(int infB){
    double sum = 0;
    for(int i = 0; i < n; ++i){
        double minP = 1e9;
        for(int j = 0; j < m[i]; ++j)
            if(bp[i][j].b >= infB)
                minP = min(minP, 1.0*bp[i][j].p);
        if(minP == 1e9)
            return;
        sum += minP;
    }
    imax = max(imax, 1.0*infB/sum);
}
int main()
{
    cin >> T;
    while(T--){
        imax = 0;
        cin >> n;
        for(int i = 0; i < n; ++i){
            cin >> m[i];
            for(int j = 0; j < m[i]; ++j)
                cin >> bp[i][j].b >> bp[i][j].p;
        }
        for(int i = 0; i < n; ++i)
            for(int j = 0; j < m[i]; ++j)
               solve(bp[i][j].b);
        cout << setprecision(3) << imax << endl;
    }
    return 0;
}
2.猴子吃桃

描述
海滩上有一堆桃子,N只猴子来分。第一只猴子把这堆桃子平均分为N份,多了一个,这只猴子把多的一个扔入海中,拿走了一份。第二只猴子接着把剩下的桃子平均分成N份,又多了一个,它同样把多的一个扔入海中,拿走了一份。第三、第四、……,第N只猴子仍是最终剩下的桃子分成N份,扔掉多了的一个,并拿走一份。
编写程序,输入猴子的数量N,输出海滩上最少的桃子数,使得每只猴子都可吃到桃子。

输入
一个整数N。
输出
输出当猴子数量为N时海滩上最少的桃子数。结果保证在int型范围内。
样例输入
2
样例输出
7
(法一)
思路:简单的枚举并迭代计算。注意ans = ans /(monkeyN-1)* monkeyN + 1;,一定要先除再乘,就因为这个改来改去改不对,气死我了😤

#include <iostream>
#include <string>
#include <stdio.h>
#include <iomanip>
using namespace std;
int main(){
    int monkeyN = 0;
    int ans = 0;
    cin >> monkeyN;
    for(int n = 1; ; ++n){
            ans = n;
            bool flag = 1;
            for(int s = 1; s <= monkeyN; ++s){
                if(ans % (monkeyN-1) == 0)
                    ans = ans /(monkeyN-1)* monkeyN + 1;
                else{
                    flag = 0;
                    break;
                }
            }
            if(flag){
                cout << ans << endl;
                break;
            }
    }
    return 0;
}

(法二)
思路:设最初有x个桃子。(x-1)mod n = 0 -> (x + n -1 ) mod n = 0
注意这样猴子就多拿走了一个桃子,是本来要扔掉的那个。暂借的n-1个没有被分掉。因此,第二只猴子来的时候,也相当于被借了n-1个,也能n等分。
所以x + n -1 必须可以n次n等分。最后计算出x = int(pow(monkeyN, monkeyN)) - (monkeyN - 1)

#include <iostream>
#include <cmath>
using namespace std;
int main(){
    int monkeyN = 0;
    cin >> monkeyN;
    if(monkeyN == 2)
        cout << 7 << endl;
    else
        cout << int(pow(monkeyN, monkeyN)) - (monkeyN - 1) << endl;
    return 0;
}
3.恼人的青蛙

描述
在韩国,有一种小的青蛙。每到晚上,这种青蛙会跳越稻田,从而踩踏稻子。农民在早上看到被踩踏的稻子,希望找到造成最大损害的那只青蛙经过的路径。每只青蛙总是沿着一条直线跳越稻田,而且每次跳跃的距离都相同。
在这里插入图片描述
如下图所示,稻田里的稻子组成一个栅格,每棵稻子位于一个格点上。而青蛙总是从稻田的一侧跳进稻田,然后沿着某条直线穿越稻田,从另一侧跳出去
在这里插入图片描述
如下图所示,可能会有多只青蛙从稻田穿越。青蛙的每一跳都恰好踩在一棵水稻上,将这棵水稻拍倒。有些水稻可能被多只青蛙踩踏。当然,农民所见到的是图4中的情形,并看不到图3中的直线,也见不到别人家田里被踩踏的水稻。
在这里插入图片描述
根据图4,农民能够构造出青蛙穿越稻田时的行走路径,并且只关心那些在穿越稻田时至少踩踏了3棵水稻的青蛙。因此,每条青蛙行走路径上至少包括3棵被踩踏的水稻。而在一条青蛙行走路径的直线上,也可能会有些被踩踏的水稻不属于该行走路径
①不是一条行走路径:只有两棵被踩踏的水稻;
②是一条行走路径,但不包括(2,6)上的水道;
③不是一条行走路径:虽然有3棵被踩踏的水稻,但这三棵水稻之间的距离间隔不相等。

请你写一个程序,确定:在一条青蛙行走路径中,最多有多少颗水稻被踩踏。例如,图4的答案是7,因为第6行上全部水稻恰好构成一条青蛙行走路径。

输入
从标准输入设备上读入数据。第一行上两个整数R、C,分别表示稻田中水稻的行数和列数,1≤R、C≤5000。第二行是一个整数N,表示被踩踏的水稻数量, 3≤N≤5000。在剩下的N行中,每行有两个整数,分别是一颗被踩踏水稻的行号(1R)和列号(1C),两个整数用一个空格隔开。而且,每棵被踩踏水稻只被列出一次。
输出
从标准输出设备上输出一个整数。如果在稻田中存在青蛙行走路径,则输出包含最多水稻的青蛙行走路径中的水稻数量,否则输出0。
样例输入
6 7
14
2 1
6 6
4 2
2 5
2 6
2 7
3 4
6 1
6 2
2 3
6 3
6 4
6 5
6 7
样例输出
7
思路:1.按顺序把点排起来,同时有数组代表稻田
2.对每个点考察后面的点能否连成功
3.优化点:if( inMap( p[i].x - delta_x, p[i].y - delta_y)) continue;
简单的避免了重复考查同一条路线
4.易错点:
inMap的判断和ans值更新一定在循环体里面,只有再扩展就不在稻田里了的才作数,否则会出现(不到稻田边就没有痕迹了)的道路也被算进去的情况。

while(map[xx][yy]){
    ++tmp;
    xx += delta_x;
    yy += delta_y;
    if(!inMap(xx, yy)){
      ans = max( ans, tmp);
      break;
    }
}
#include <iostream>
#include <set>
#include <string>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <string.h>
#include <queue>
#include <limits.h>
#include <iomanip>
using namespace std;
int row, col, n;
bool map[5005][5005] = {};
struct Point{
    int x,y;
}p[5005] = {};
bool cmp( Point a, Point b){
    if( a.x !=  b.x)
        return a.x < b.x;
    else
        return a.y < b.y;
}
bool inMap(int x, int y){
    if( 1 <= x && x <= row && 1 <= y && y <= col)
        return 1;
    else
        return 0;
}
int main(){
    int ans = 2;
    cin >> row >> col >> n;
    for( int i = 0; i < n; ++i){
        cin >> p[i].x >> p[i].y;
        map[p[i].x][p[i].y] = 1;
    }
    sort( p, p + n, cmp);
    for( int i = 0; i < n; ++i){
        for( int j = i+1; j < n; ++j){
            int tmp = 1;
            int delta_x = p[j].x - p[i].x;
            int delta_y = p[j].y - p[i].y;
            if( inMap( p[i].x - delta_x, p[i].y - delta_y))
                continue;
            int xx = p[j].x;
            int yy = p[j].y;
            while(map[xx][yy]){
                ++tmp;
                xx += delta_x;
                yy += delta_y;
                if(!inMap(xx, yy)){
                    ans = max( ans, tmp);
                    break;
                }
            }
        }
    }
    cout << ( ans < 3 ? 0 : ans) << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值