时间限制 1000 ms
内存限制 128 MB
题目描述
有形如:ax^3+bx^2+cx+d=0 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值> =1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。
提示:记方程f(x)=0,若存在2个数x1和x2,且x1< x2,f(x1)*(x2)< 0,则在(x1,x2)之间一定有一个根。
输入数据
输入该方程中各项的系数 (a,b,c,d (a,b,c,d 均为实数),
输出数据
由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后 22 位。
样例输入
1 -5 -4 20
样例输出
-2.00 2.00 5.00
#include <iostream> #include <iostream> #include <cstring> #include <cmath> #include <algorithm> #include <iomanip> using namespace std; double a, b, c, d; #define f(x) (a*(x)*(x)*(x)+b*(x)*(x)+c*(x)+d) void ef(double s, double e) { if (f(s) * f(e) <= 0) { double mid = (s + e) / 2.0; if (fabs(f(mid)) <= 1e-8) { cout<<setiosflags(ios::fixed) << setprecision(2) << mid << " "; return; } if (f(mid) * f(s) < 0) ef(s, mid); else ef(mid, e); } } int main() { cin >> a >> b >> c >> d; for (double s = -101; s <= 101; s += 1) { ef(s, s + 1); } return 0; }
时间限制 1000 ms
内存限制 64 MB
题目描述
有n根小木棒,任选三根木棒组成一个三角形,问三角形周长最大是多少。(保证至少存在一种选法能组成三角形)
输入数据
第一行为一个正整数n,3=<n<=100 第二行为n个正整数,代表小木棒长度,不超过100.
输出数据
三角形周长的最大值
样例输入
5 1 2 3 4 5
样例输出
12
解法1:
#include<iostream> #include<algorithm> using namespace std; const int MAX_N = 105; int cmp(const void* a, const void* b) { return *(int*)a - *(int*)b; } void solve(int n, int* a) { qsort(a, n, sizeof(a[0]), cmp); int sum = 0; for (int i = n - 1; i > 1; --i) { if (a[i] + a[i - 1] > a[i - 2]) if (a[i] + a[i - 2] > a[i - 1]) if (a[i - 1] + a[i - 2] > a[i]) { sum = a[i] + a[i - 1] + a[i - 2]; break; } } cout << sum; } int main() { int n, a[MAX_N]; cin >> n; for (int i = 0; i < n; ++i) cin >> a[i]; solve(n, a); return 0; }
时间限制 1000 ms
内存限制 64 MB
题目描述
如果一个质数能被表示为三个不同的质数的和的形式,那么我们称它为立方质数。现在给你一个数n,判断它是不是立方质数。
输入数据
正整数n,n<=1000
输出数据
Yes或者No
样例输入
19
样例输出
Yes
解法1
#include <iostream> #include <cmath> using namespace std; //判断是否为质数 bool isPrime(int num) { if (num <= 3) { return num > 1; } // 不在6的倍数两侧的一定不是质数 if (num % 6 != 1 && num % 6 != 5) { return false; } for (int i = 5; i <= sqrt(num); i += 6) { if (num % i == 0 || num % (i + 2) == 0) { return false; } } return true; } int main() { int n; cin >> n; bool flag = false; if (!isPrime(n)) { cout << "No" << endl; } else { for (int i = 1; i <= n; i++) { if (isPrime(i)) { for (int j = i + 1; j <= n; j++) { if (isPrime(j) && isPrime(n - i - j) && (n - i - j) != i && (n - i - j) != j) { flag = true; } } } } if (flag) cout << "Yes" << endl; else cout << "No" << endl; } return 0; }
时间限制 1000 ms
内存限制 64 MB
题目描述
有n盏灯,编号都是1-n,初始灯都是关着的。有n个人,第1个人会打开所有的灯,第2个人会按下所有编号为2的倍数的灯的开关(这些灯将被关掉),第3个人会按下所有编号为3的倍数的开关,以此类推,第n个人会按下所有编号为n的倍数的开关。问最后有几盏灯是亮着的。
输入数据
一个正整数n,n<100000
输出数据
亮着的灯的数量
样例输入
5
样例输出
2
解法1:
#include <iostream> using namespace std; int check(int x) { int cnt = 0; int i; for (i = 1; i * i < x; ++i) { if (!(x % i)) { cnt += 2; } } if (i * i == x) { ++cnt; } return cnt; } int main() { int n; cin >> n; int cnt = 0; for (int i = 1; i <= n; ++i) { if (check(i) % 2) { ++cnt; } } cout << cnt << endl; return 0; }
解法2:
# include "iostream" # include "vector" # include "numeric" using namespace std; #define MAX_SIZE 100000 int main(){ int n; cin >>n; vector<int> p(n+1, 1); for(int i = 2; i <= n; i++){ for(int j = 1; j*i <= n; j++){ if(p[j*i] == 1) p[j*i] = 0; else p[j*i] = 1; } } p[0] = 0; cout << accumulate(p.begin(), p.end(), 0) << endl; // 累加范围,和累加初值 return 0; }
解法3:
#include <iostream> using namespace std; int main(){ int n; cin >> n; int i = 1; for(; i * i <= n; i++){} cout << i - 1 << endl; return 0; }
时间限制 1000 ms
内存限制 64 MB
题目描述
小明刚买了一个机械键盘,但他在用机械键盘打字的时候发现键盘的Home键和End键坏掉了,于是他在打字的时候光标有时会突然跑到行首,有时又会突然跑到行尾,现在给你键盘的输入,求最后屏幕上的字符串。
输入数据
输入数据为一行字符串,字符串只包含小写英文字母,’[‘符号以及’]‘符号,’['代表按下了Home键,‘]’代表按下了End键,字符串长度不超过100000。
输出数据
输出最后屏幕上的字符串。
样例输入
xiechengxuz[henhao]wan
样例输出
henhaoxiechengxuzwan
样例说明
可能出现多个’[‘和’]’,也可能没有’[‘和’]’
解法1:
# include <iostream> # include <string> # include <queue> using namespace std; deque<string> q; string buf; void fun(int flag, string& buf) { if (flag) q.push_back(buf); else q.push_front(buf); buf.clear(); } int main() { string s; cin >> s; int flag = 0;// flag=0,放在前面; flag =1, 放在后面 for (int i = 0; i < s.length(); i++) { if (s[i] != '[' && s[i] != ']') { buf += s[i]; }else if (s[i] == '[') { fun(flag, buf); flag = 0; } else { fun(flag, buf); flag = 1; } } fun(flag, buf); for (auto i : q) cout << i; }
时间限制 1000 ms
内存限制 128 MB
题目描述
农民约翰的母牛总是生产出最好的肋骨。你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们。
农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋骨,每次还剩下的肋骨上的数字都组成一个质数,举例来说:
7 3 3 1
全部肋骨上的数字 7331是质数;三根肋骨 733是质数;二根肋骨 73 是质数;当然,最后一根肋骨 7 也是质数。
7331 被叫做长度 4 的特殊质数。
写一个程序对给定的肋骨的数目 N (1< =N< =8),求出所有的特殊质数。数字1不被看作一个质数。
输入数据
单独的一行包含 N 。
输出数据
按顺序输出长度为 N 的特殊质数,每行一个。
并按大小顺序排列(从小到大).
样例输入
4
样例输出
2333 2339 2393 2399 2939 3119 3137 3733 3739 3793 3797 5939 7193 7331 7333 7393
解法1:
#include<iostream> #include<cmath> #include <queue> using namespace std; bool isPrime(int num) { //判断是否为质数 if (num <= 3) { return num > 1; } if (num % 6 != 1 && num % 6 != 5) { // 不在6的倍数两侧的一定不是质数 return false; } for (int i = 5; i <= sqrt(num); i += 6) { if (num % i == 0 || num % (i + 2) == 0) { return false; } } return true; } int main() { queue <int> q; int n, m = 4; int a[] = { 2,3,5,7 }; // 单独一个数是质数 int b[] = { 1,3,7,9 }; //一这些数字为结尾的,可能是质数 cin >> n; for (int i = 0; i < 4; i++) q.push(a[i]); for (int i = 2; i <= n; i++) { int l = m; m = 0; for (int j = 0; j < l; j++) { for (int k = 0; k < 4; k++) //选择枚举b[k] if (isPrime(q.front() * 10 + b[k])) q.push(q.front() * 10 + b[k]), m++; q.pop(); } } while (!q.empty()) { cout << q.front() << endl; q.pop(); } return 0; }
解法2
#include <iostream> #include <vector> using namespace std; int mn = 1, mx = 1; vector<int> bones; bool isprime(int x) { if (x == 2) { return true; } if (x == 1 || !(x % 2)) { return false; } for (int i = 3; i * i <= x; i += 2) { if (!(x % i)) { return false; } } return true; } void dfs(int x) { if (x >= mn && x < mx) { bones.push_back(x); return; } x *= 10; for(int i = 1; i < 10; ++i) { if (isprime(x + i)) { dfs(x + i); } } } int main() { int n; cin >> n; while (--n) { mn *= 10; mx = mn; } mx *= 10; dfs(0); for (int i : bones) { cout << i << endl; } return 0; }
时间限制 1000 ms
内存限制 128 MB
题目描述
给出一个小于2^32的正整数。这个数可以用一个32位的二进制数表示(不足32位用0补足)。我们称这个二进制数的前16位为“高位”,后16位为“低位”。将它的高低位交换,我们可以得到一个新的数。试问这个新的数是多少(用十进制表示)。
例如,数1314520用二进制表示为0000 0000 0001 0100 0000 1110 1101 1000(添加了11个前导0补足为32位),其中前16位为高位,即0000 0000 0001 0100;后16位为低位,即0000 1110 1101 1000。将它的高低位进行交换,我们得到了一个新的二进制数0000 1110 1101 1000 0000 0000 0001 0100。它即是十进制的249036820。
输入数据
一个小于 232232 的正整数
输出数据
将新的数输出
样例输入
1314520
样例输出
249036820
解法1:
#include<iostream> using namespace std; int main() { unsigned long long x; cin >> x; cout << ((x & 0x0000ffff) << 16 | (x & 0xffff0000) >> 16) << endl; }
时间限制 1000 ms
内存限制 64 MB
题目描述
我们有n根的木棍。现在从这些木棍中切割出来m条长度相同的木棍,问这m根木棍最长有多长?
输入数据
第一行输入两个数字,n(1<=n<=1000)为木棍数目,m(1<=m<=1000)为需要切割出的相同长度的木棍数目 随后n个正整数,表示原始木棍的长度(<=10000)
输出数据
每组输出一行结果,表示切割后绳子的最长长度(保留两位小数)
样例输入
4 5 5 6 7 8
样例输出
4.00
解法1
#include <iostream> using namespace std; #include <vector> #include <iomanip> #include <cmath> int main() { int n,m; cin >>n>> m; vector<int> v; double max=0; for (int i = 0; i < n; i++) { int t; cin >> t; v.push_back(t); if (t > max) max = t; } double s = 0, e = max; double mid; while (s + 0.01 < e) { int cnt = 0; mid = round(((s + e) / 2.00) * 100) / 100.00; //四舍五入 for (int i = 0; i < n; i++) cnt += (double)(v[i] / mid); if (cnt >= m) s = mid; else e = mid; } cout << setiosflags(ios::fixed) << setprecision(2) << s ; }
时间限制 1000 ms
内存限制 64 MB
题目描述
有一条河,河中间有一些石头,已知石头的数量和相邻两块石头之间的距离。现在可以移除一些石头,问最多移除m块石头后(首尾两块石头不可以移除),相邻两块石头之间的距离的最小值最大是多少。
输入数据
第一行输入两个数字,n(2<=n<=1000)为石头的个数,m(0<=m<=n-2)为可移除的石头数目 随后n-1个数字,表示顺序和相邻两块石头的距离d(d<=1000)
输出数据
输出最小距离的最大值
样例输入
4 1 1 2 3
样例输出
3
解法1:
#include <stdio.h> int n, m,ans; int d[1005]; int l[1005] = { 0 }; int main() { scanf("%d%d", &n, &m); for (int i = 2; i <= n; i++) { scanf("%d", &d[i]); l[i] = d[i] + l[i - 1]; } int left=0,right=l[n]; while(left<=right) { int now=0,mid=(left+right)>>1,s=0; for(int i=2;i<=n;++i) { if(l[i]-l[now]<mid) ++s; else now=i; } if(s>m) right=mid-1; else { ans=mid; left=mid+1; } } printf("%d",ans); return 0; }
时间限制 1000 ms
内存限制 64 MB
题目描述
楼梯有n阶,可以一步上一阶、两阶或三阶,问有多少种不同的走法
由于答案很大,mod(1e9+7)输出
输入数据
一个正整数n,代表楼梯的阶数,n<=1000000
输出数据
方案数
样例输入
3
样例输出
4
解法1
# include <iostream> # include <cmath> # include <vector> using namespace std; int main() { long n; cin >> n; long long f[3]; f[0] = 1; f[1] = 2; f[2] = 4; int mod = (1e9 + 7); long long ans; if (n < 3) { ans = f[n - 1]; } else { for (long i = 3; i < n; i++) { long long t; t = f[0]; f[0] = f[1]; f[1] = f[2]; f[2] = (t + f[0] + f[1]) % mod; } ans = f[2]; } cout << ans; }
时间限制 1000 ms
内存限制 128 MB
题目描述
一个快递公司要将n个包裹分别送到n个地方,并分配给邮递员小K一个事先设定好的路线,小K需要开车按照路线给的地点顺序相继送达,且不能遗漏一个地点。小K得到每个地方可以签收的时间段,并且也知道路线中一个地方到下一个地方的距离。若到达某一个地方的时间早于可以签收的时间段,则必须在这个地方停留至可以签收,但不能晚于签收的时间段,可以认为签收的过程是瞬间完成的。
为了节省燃料,小K希望在全部送达的情况下,车的最大速度越小越好,就找到了你给他设计一种方案,并求出车的最大速度最小是多少。
输入数据
第 11 行为一个正整数 n (n<2×104),n (n<2×104), 表示需要运送包裹的地点数。
下面 nn 行,第 i+1i+1 行有 33 个正整数 xi,yi,si,xi,yi,si, 表示按路线顺序给出第 ii 个地点签收包裹的时间段为 [xi,yi],[xi,yi], 即最早为距出发时刻 xi,xi, 最晚为距出发时刻 yi,yi, 从前一个地点到达第 ii 个地点距离为 si,si, 且保证路线中 xixi 递增。
可以认为 s1s1 为出发的地方到第 11 个地点的距离,且出发时刻为 00 。
输出数据
仅包括一个整数,为车的最大速度最小值,结果保留两位小数。
样例输入
3 1 2 2 6 6 2 7 8 4
样例输出
2.00
样例说明
第一段用1的速度在时间2到达第1个地点,第二段用0.5的速度在时间6到达第2个地点,第三段用2的速度在时间8到达第3个地点。
解法1:
#include <stdio.h> #define maxn 200005 long double st=0,en=1e9,mid; int i,n; int v[maxn][3]; bool check(long double x) { long double minT, totalT=0; for (int i = 0; i < n; i++) { minT = v[i][2] / x; totalT = minT + totalT; if (totalT < v[i][0]) totalT = v[i][0]; else if (totalT > v[i][1]) return false; } return true; } int main(){ scanf("%d",&n); for(i=0;i<n;i++)scanf("%d%d%d",&v[i][0], &v[i][1], &v[i][2]); while(en-st>1e-9){ mid=(en+st)/2.00; if(check(mid)) en=mid; else st=mid; } printf("%.2f",double(st)); return 0; }
时间限制 1000 ms
内存限制 64 MB
题目描述
有ABC三根杆和一些圆盘,开始的时候圆盘从小到大摞在A杆上,小盘在上大盘在下,规定如果圆盘p摞在圆盘q上面,那么rp<=rq,rp和rq为p和q的半径。
现在有若干个圆盘,半径从1到n,半径为i的圆盘有i个,每次操作可以移动一个圆盘,问把所有圆盘从A杆移动到C杆上最少需要几次操作。 由于最终答案可能很大,所以答案对1e9+7取模输出。
输入数据
一个正整数n,n<=1e5
输出数据
最少操作次数
样例输入
2
样例输出
4
样例说明
第一步把半径为1的圆盘从A放到B 第二步和第三步把两个半径为2的圆盘从A放到C 第四步把半径为1的圆盘从B放到C
解法1:
#include <iostream> using namespace std; int main() { int n; cin >> n; long long cnt=0; long long mod = 1e9 + 7; for (long long i = 1; i <= n; i++) { cnt =(cnt*2+i)%mod; } cout << cnt<<endl; }
时间限制 1000 ms
内存限制 128 MB
题目描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
输入数据
输入的第一行有两个整数 T (1≤T≤1000) 和 M (1≤M≤100) 用一个空格隔开,T 代表总共能够用来采药的时间 ,M 代表山洞里的草药的数目。接下来的 M 行每行包括两个在 1 到100之间(包括 1 和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出数据
输出包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
样例输入
70 3 71 100 69 1 1 2
样例输出
3
解法1
#include <iostream> #include <cstring> using namespace std; const int maxn = 1e4; int f[maxn]; //f:草药的总价值 int w[maxn], val[maxn]; //w: 时间花费 val:草药价值 void solve(int m, int t) { memset(f, 0, sizeof f); for (int i = 1; i <= m; i++) { for (int v = t; v > 0; v--) { if (v >= w[i]) f[v] = max(f[v], f[v - w[i]] + val[i]); } } cout << f[t]; } int main() { int m, t; //t 采药的时间,m草药的数目 cin >> t >> m; for (int i = 1; i <= m; i++) { cin>>w[i] >> val[i] ; } solve(m,t); return 0; }
时间限制 1000 ms
内存限制 128 MB
题目描述
有一个箱子容量为v(正整数,o≤v≤20000),同时有n个物品(o≤n≤30),每个物品有一个体积 (正整数)。要求从 n 个物品中,任取若千个装入箱内,使箱子的剩余空间为最小。
输入数据
第一行,一个整数,表示箱子容量;
第二行,一个整数,表示有 n 个物品;
接下来 n 行,分别表示这 n 个物品的各自体积。
输出数据
一个整数,表示箱子剩余空间。
样例输入
24 6 8 3 12 7 9 7
样例输出
0
解法1
# include <iostream> # include <algorithm> # include <cmath> using namespace std; int v; int n; int a[35]; int dp[20005]; int main() { cin >> v >> n; for (int i = 1; i <= n; i++) { cin >> a[i]; } for(int i=1;i<=n;i++) for(int j=v;j>=a[i];j--) dp[j]=max(dp[j],dp[j-a[i]]+a[i]); int minV = v - dp[v]; cout << minV; return 0; }
时间限制 1000 ms
内存限制 128 MB
题目描述
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足T1< …< Ti> Ti+1> …> TK(1< =i< =K)。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
输入数据
输入的第一行是一个整数 N (2≤N≤100), 表示同学的总数。第一行有 n 个整数,用空格分隔,第 i 个整数 Ti (130≤Ti≤230) 是第 i 位同学的身高(厘米)。
输出数据
输出包括一行,这一行只包含一个整数,就是最少需要几位同学出列。
样例输入
8 186 186 150 200 160 130 197 220
样例输出
4
解法一
# include <iostream> using namespace std; int l[105],r[105],h[105],dp[105]; int main() { int n; cin>>n; for(int i=1;i<=n;i++){ cin>>h[i]; l[i]=r[i]=1; } for(int i=n-1;i>=1;i--){ for (int j=i+1;j<=n;j++) { if(h[i]>h[j]&&r[i]<=r[j]+1) r[i]=r[j]+1; } } for(int i=2;i<=n;i++){ for(int j=1;j<i;j++){ if(h[i]>h[j]&&l[i]<=l[j]+1) l[i]=l[j]+1; } } int max=0; for(int i=1;i<=n;i++){ dp[i]=l[i]+r[i]-1; if(dp[i]>max) max=dp[i]; } cout<<n-max; }
时间限制 1000 ms
内存限制 128 MB
题目描述
棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,A点(0, 0)、B点(n, m)(n, m为不超过15的整数),同样马的位置坐标是需要给出的。现在要求你计算出卒从A点能够到达B点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入数据
一行四个数据,分别表示 B 点坐标和马的坐标。
输出数据
一个数据,表示所有的路径条数。
样例输入
6 6 3 3
样例输出
6
解法1
#include<iostream> #define ll long long using namespace std; bool a[30][30]; ll dp[30][30]; //B(n,m) ma(x,y) int main() { int n, m, x, y; cin >> n >> m >> x >> y; dp[1][1] = 1; n++; m++; x++; y++; a[x][y] = 1; a[x - 1][y + 2] = 1; a[x - 1][y - 2] = 1; a[x + 1][y + 2] = 1; a[x + 1][y - 2] = 1; a[x - 2][y - 1] = 1; a[x - 2][y + 1] = 1; a[x + 2][y - 1] = 1; a[x + 2][y + 1] = 1; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if ((i != 1 || j != 1) && !a[i][j]) dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; } } cout << dp[n][m]; }
时间限制 1000 ms
内存限制 128 MB
题目描述
上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。
游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再次吹哨子时,传球停止,此时,拿着球没传出去的那个同学就是败者,要给大家表演一个节目。
聪明的小蛮提出了一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m次以后,又回到小蛮手里。两种传球方法被视作不同的方法,当且仅当这两种方法中,接到球的同学按接球顺序组成的序列是不同的。比如有三个同学1号、2号、3号,并假设小蛮为1号,球传了三次回到小蛮手里的方式有1-> 2-> 3-> 1和1-> 3-> 2-> 1,共2种。
输入数据
输入共一行,有两个用空格隔开的整数 n,m (3≤n≤30,1≤m≤30)。
输出数据
输出共一行,有一个整数,标示符合题意的方法数。
样例输入
3 3
样例输出
2
样例说明
40%的数据满足:3< =n< =30 1< =m< =20
100%的数据满足:3< =n< =30 1< =m< =30
解法1:
dp[i][j]: 传了i次球,传到编号为j的同学的方法数。
#include<iostream> using namespace std; int dp[40][40]; int main() { int n, m, x, y; cin >> n >> m; dp[0][1] = 1; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { x = j - 1; y = j + 1; if (x == 0) x = n; if (y == n + 1) y = 1; dp[i][j] = dp[i - 1][x] + dp[i - 1][y]; } } cout << dp[m][1]; }
时间限制 1000 ms
内存限制 64 MB
题目描述
给定1×N的单行矩阵,矩阵每个元素都是-127到+127之间的整数。请找到一个连续子矩阵,使得其元素之和最大。例如行矩阵0 -2 -7 0 -2 11 -4 13 -5 -2,最大子矩阵和为11+(-4)+13=20.
输入数据
多组测试数据,每组数据的第一行为一个整数 N (N<=100),第二行包含N个整数,为行矩阵的N个元素,每个元素介于-127到127之间。
输出数据
最大子矩阵之和,每组对应一行。
样例输入
10 0 -2 -7 0 -2 11 -4 13 -5 -2
样例输出
20
解法1
#include <stdio.h> int N; int a[105]; int main(){ while(scanf("%d",&N)!=EOF){ for(int i=0;i<N;i++ ){ scanf("%d",&a[i]); } int sum=0; int max=a[0]; for(int i=0;i<N;i++){ sum+=a[i]; if(sum<0) sum=0; if(sum>max) max=sum; } printf("%d\n",max); } }
时间限制 1000 ms
内存限制 64 MB
题目描述
给定N×N矩阵,矩阵元素都是-127到+127之间的整数。请找到一个子矩阵,使得其元素之和最大。例如给定4*4矩阵 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2 最大子矩阵为 9 2 -4 1 -1 8 最大子矩阵和为9+2+(-4)+1+(-1)+8 = 15.
输入数据
多组测试数据,每组测试数据的第一行整数 N (N<=100)。接下来N行元素,每行N个元素,每个元素介于-127到127之间。
输出数据
最大子矩阵元素之和,每组测试数据对应一行。
样例输入
4 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -1 8 0 -2
样例输出
15
解法1
#include <stdio.h> #include <string.h> int n; int a[105][105]; int temp[105]; int main(){ while(scanf("%d",&n)!=EOF){ for(int i=0;i<n;i++ ){ for(int j=0;j<n;j++){ scanf("%d",&a[i][j]); } } int max=-32767; for(int i=0;i<n;i++){ memset(temp,0,sizeof(temp)); for(int j=i;j<n;j++){ int sum=0; int tempmax=-32767; for(int k=0;k<n;k++){ temp[k]+=a[j][k]; sum+=temp[k]; if(sum<0) sum=0; if(sum>tempmax) tempmax=sum; } if(tempmax>max) max=tempmax; } } printf("%d\n",max); } }
时间限制 2000 ms
内存限制 64 MB
题目描述
作为一个有很多游戏想买但囊中羞涩的大学生,小明决定在这个暑假开始打工赚钱。经过一段时间的寻找,他一共找到了n个打工的招聘广告,其中第i个打工的日期从li开始,到ri为止,一共付给他ci元钱。因为这些打工的时间都相互冲突,所以同一天小明最多参加一个打工,并且一个打工一旦开始,就必须一直工作到结束,不能中途退出。现在小明想要知道,这个暑假他打工最多能得到多少钱?
输入数据
第一行一个整数n(1≤n≤10000001≤n≤1000000),表示招聘广告的数量。 接下来一共n行,每行3个整数li,ri,ci(1≤li≤ri≤1000000,1≤ci≤10000000001≤li≤ri≤1000000,1≤ci≤1000000000),表示打工的开始时间,结束时间和报酬。
输出数据
一行一个整数k,表示小明最多能够得到的钱数。
样例输入
3 1 2 3 3 4 3 2 3 5
样例输出
6
解法1
#include <iostream> #include <algorithm> #include <math.h> using namespace std; struct job{ int l,r,w; }a[1100000]; long long f[1100000]; int n,id; bool cmp(job x,job y){ return (x.r<y.r )||(x.r==y.r && x.l<y.l); } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i].l>>a[i].r>>a[i].w; } sort(a+1,a+n+1,cmp); id=1; for(int i=1;i<=a[n].r;i++){ f[i]=f[i-1]; while(i==a[id].r&&id<=n){ // 可能有多个项目的结束时间一致 f[i]=max(f[i],f[a[id].l-1]+a[id].w); id++; } } cout<<f[a[n].r]; }
时间限制 1000 ms
内存限制 128 MB
题目描述
给定一个信封,最多只允许粘贴N张邮票,计算在给定M(N+M< =10)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大max ,使得1~max之间的每一个邮资值都能得到。
例如,N=3,M=2,如果面值分别为1分、4分,则在l分~6分之间的每一个邮资值都能得到(当然还有8分、9分和12分):如果面值分别为1分、3分,则在1分~7分之间的每一个邮资值都能得到。可以验证当N=3,M=2时,7分就是可以得到连续的邮资最大值,所以MAX=7,面值分别为l分、3分。
样例输入:共一行,两个整数,分表为N与M的值。
输入数据
一行,分别为 N,M。
输出数据
两行。
第一行为 mm 种邮票的面值,按升序排列,各数之间用一个空格隔开。
第二行为最大值。
样例输入
3 2
样例输出
1 3 max=7
题解1
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> using namespace std; int m,n,ans,a[1005],b[1005],s[1005]; int stamp(int t) { int i,res; for (i=1; i<=1000; i++) b[i]=1e6; for (i=1; i<=t; i++) b[a[i]]=1; res=0; do { res++; for (i=1; i<=t; i++) if (res>a[i] && b[res-a[i]]+1<b[res]) b[res]=b[res-a[i]]+1; }while (b[res]<=m); return res; } void find(int i) { int k,z; z=stamp(i-1); if (i>n) { int ii; if (z-1>ans) { ans=z-1; for (ii=2; ii<=n; ii++) s[ii]=a[ii]; } return; } for (k=z; k>=a[i-1]+1; k--) { a[i]=k; find(i+1); } } int main() { int i; cin>>m>>n; a[1]=1; find(2); s[1]=1; for (i=1; i<n; i++) cout<<s[i]<<" "; cout<<s[i]; cout<<endl; cout << "MAX=" << ans<< endl; return 0; }
时间限制 1000 ms
内存限制 128 MB
题目描述
某国为了防御敌国的导弹袭击,研发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试验阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入数据
输入数据只有一行,该行包含若干个数据,之间用半角逗号隔开,表示导弹依次飞来的高度(导弹最多有 20枚,其高度为不大于 3×103 的正整数)。
输出数据
输出数据只有一行,该行包含两个数据,之间用半角逗号隔开。第一个数据表示这套系统最多能拦截的导弹数;第二个数据表示若要拦截所有导弹至少要再添加多少套这样的系统。
样例输入
389,207,155,300,299,170,158,65
样例输出
6,1
解法1
#include <iostream> #include <algorithm> using namespace std; const int N = 100010; int a[N], d1[N], d2[N], n; int main() { char ch; int n=0; while (1){ cin >> a[++n]; ch= getchar(); if(ch=='\n') break; }; int len1 = 1, len2 = 1; //初始长度为1 d1[1] = a[1]; //用于求不上升序列长度 d2[1] = a[1]; //用于求上升序列长度 for (int i=2; i<=n; i++) { //从a[2]开始枚举每个数(a[1]已经加进去了) if (d1[len1] >= a[i]) d1[++len1] = a[i]; //如果满足要求(不上升)就加入d1 else { //否则用a[i]替换d1中的一个数 int p1 = upper_bound(d1 + 1, d1 + 1 + len1, a[i], greater<int>()) - d1; d1[p1] = a[i]; } if (d2[len2] < a[i]) d2[++len2] = a[i]; //同上 else { int p2 = lower_bound(d2 + 1, d2 + 1 + len2, a[i]) - d2; d2[p2] = a[i]; } } cout << len1 <<"," << len2-1; //输出 return 0; //结束 }
时间限制 1000 ms
内存限制 128 MB
题目描述
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。
输入数据
输入包括两行,第一行是一个整数 n (1<=n<103),n (1<=n<103), 表示果子的种类数。第二行包含 n 个整数,用空格分隔,第 i个整数 ai (1<=ai<2×103) 是第 ii 种果子的数目。
输出数据
输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 231。
样例输入
3 1 2 9
样例输出
15
解法1
#include<bits/stdc++.h> using namespace std; #define maxn 10005 int n; int a[maxn]; int main(){ ios::sync_with_stdio(false);cin.tie(0); cin>>n; priority_queue<int, vector<int>, greater<int>> que; for(int i = 0; i<n; i++){ cin>>a[i]; que.push(a[i]); } if(n==1){ cout<<0; return 0; } int ans = 0; while(!que.empty()){ int t1 = que.top(); que.pop(); int t2 = que.top(); que.pop(); ans+=t1+t2; if(que.empty())break; que.push(t1+t2); } cout<<ans; return 0; }
时间限制 1000 ms
内存限制 128 MB
题目描述
给定一些不同的一位数字,你可以从这些数字中选择若干个,并将它们按一定顺序排列,组成一个整数,把剩下的数字按一定顺序排列,组成另一个整数。组成的整数不能以0开头(除非这个整数只有1位)。
例如,给定6个数字,0,1,2,4,6,7,你可以用它们组成一对数10和2467,当然,还可以组成其他的很多对数,比如210和764,204和176。这些对数中两个数差的绝对值最小的是204和176,为28。
给定N个不同的0~9之间的数字,请你求出用这些数字组成的每对数中,差的绝对值最小的一对(或多对)数的绝对值是多少?
输入数据
第一行包括一个数 T (T≤1000), 为测试数据的组数。
每组数据包括两行,第一行为一个数 N (2≤N≤10), 表示数字的个数。下面一行为 N 个不同的一位数字。
输出数据
T 行,每行一个数,表示第 i 个数据的答案。即最小的差的绝对值。
样例输入
2 6 0 1 2 4 6 7 4 1 6 3 4
样例输出
28 5
解法1
#include<bits/stdc++.h> using namespace std; int n; int a[12]; int vis[12]; void solve(){ cin>>n; for(int i = 1; i<=n; i++) cin>>a[i]; sort(a+1, a+n+1); if(n==2){ cout<<a[2]-a[1]<<'\n'; return; } if(n&1){ if(a[1]==0) swap(a[1], a[2]); int x = 0; for(int i = 1; i<=n/2+1; i++) x = 10*x+a[i]; int y = 0; for(int i = n; i>=n/2+2; i--) y = 10*y+a[i]; cout<<abs(x-y)<<'\n'; return; } int ret = 1e9; for(int i = 2; i<=n; i++) { if(a[i-1]==0) continue; memset(vis, 0, sizeof(vis)); int x = a[i], y = a[i-1]; int l = 1, r = n; vis[i] = vis[i-1] = 1; for(int j = 1; j<=n/2-1; j++){ while(vis[l]) l++; while(vis[r]) r--; x = 10*x+a[l]; y = 10*y+a[r]; vis[l] = vis[r] = 1; l++, r--; } ret = min(ret, abs(x-y)); } cout<<ret<<'\n'; } int main(){ ios::sync_with_stdio(false); cin.tie(0); int tt; cin>>tt; while(tt--){ solve(); } return 0; }
时间限制 1000 ms
内存限制 128 MB
题目描述
我们知道,词都是按照词牌来填的,上帝为了考验小杉,只给了他四种词牌,但只要压韵就算符合词牌。
小杉已经想好了N个意境优美的句子,每个句子都有一个韵脚。
符合要求的词的句式应当有如下四种" XXYY" ," XYXY" ," XYYX" ," XXXX" ,其中X或Y表示韵脚。
现在小杉想知道,从他想的N个句子之中,最多能按顺序挑选出几首符合条件的词。
并且词的句子间不能交错,比如你选了1 4 6 8做为一首诗,那么7你就不能再选了。
输入数据
每组测试数据的
第一行有一个数 N (N≤4000)。
第二行有N个不超10^{3}的正整数,第i个整数表示第i个句子的韵脚,整数相同表示韵脚相同。
3030 的数据 N≤100N≤100
输出数据
对每组测试数据输出一行,仅有一个数字,表示小杉最多能挑出几首词来。
样例输入
12 1 2 4 2 3 1 2 2 1 1 2 2
样例输出
2
样例说明
样例最多可以挑出两首词,一种方案如下:
1 2 4 6/9 10 11 12
解法1
#include <iostream> using namespace std; int a[10000]; int main(){ int n; cin>>n; for(int i=0;i<n;i++) cin>>a[i]; int s=0; int cnt=0; int j; int ans=0; for(int i=0;i<n;i++){ for(j=s;j<i;j++){ if(a[i]==a[j]){ cnt++; a[i]=a[j]=0; //标记已用 break; } } if(cnt==2){ //两对相同的数 cnt =0; s=i; ans++; } } cout<<ans; return 0; }
时间限制 1000 ms
内存限制 128 MB
题目描述
一个单位时间任务是恰好需要一个单位时间完成的任务。给定一个单位时间任务的有限集S。关于S 的一个时间表用于描述S 中单位时间任务的执行次序。时间表中第1 个任务从时间0 开始执行直至时间1 结束,第2 个任务从时间1 开始执行至时间2 结束,…,第n个任务从时间n-1 开始执行直至时间n结束。具有截止时间和误时惩罚的单位时间任务时间表问题可描述如下:
(1) n 个单位时间任务的集合S={1,2,…,n}(n≤500)
(2) 任务i的截止时间d[i], 1≤i≤n, 1≤d[i]≤n,即要求任务i在时间d[i]之前结束;
(3) 任务i 的误时惩罚1≤w[i]< 1000,1≤i≤n,即任务i 未在时间d[i]之前结束将招致w[i]的惩罚;若按时完成则无惩罚。
任务时间表问题要求确定S 的一个时间表(最优时间表)使得总误时惩罚达到最小。
输入数据
第一行是正整数 n, 表示任务数。接下来的 2 行中,每行有 n个正整数,分别表示各任务的截止时间和误时惩罚。
输出数据
将计算出的最小总误时惩罚输出
样例输入
7 4 2 4 3 1 4 6 70 60 50 40 30 20 10
样例输出
50
解法1
#include <iostream> #include <algorithm> using namespace std; struct task{ int d,w; }a[505]; bool cmp(task t1,task t2) { return t1.w>t2.w; } int main(){ int d[505]; int w[505]; int n; cin>>n; for(int i=0;i<n;i++) cin>>a[i].d; int total=0; for(int i=0;i<n;i++) { cin>>a[i].w; total+=a[i].w; } sort(a,a+n,cmp); int flag[505]={0}; int ans=0; for(int i=0;i<n;i++){ for(int j=a[i].d-1;j>=0;j--){ if(flag[j]==0){ ans+=a[i].w; flag[j]=1; break; } } } cout<<total-ans; return 0; }
时间限制 1000 ms
内存限制 64 MB
题目描述
前不久 sqy 老师花了大价钱,去做了一个帅气的锡纸烫。有着商业眼光的 sqy 一下子发现了大商机,于是他自己开了一家美容美发店。
sqy 找了刚刚做完纹理烫的大预言家 cbj 预测了未来,发现每个顾客都只在白天来美发店,并且第一次来店里的时候都会充一次价值 xi 的卡,然后从第二天开始,每天白天都会来这里打理头发,而 sqy 仅收取成本价 1 元钱来吸引顾客,直到把卡掏空为止,这个顾客就再也不会回来。
黑心商人 sqy 找大预言家要来了每个顾客的充卡时间和充值金额,他准备在某一天晚上跑路,他想知道自己最多能卷走多少钱。
输入数据
第一行包括一个整数 n(1≤n≤105)表示有 n 个顾客。 接下来共 n 行,每i+1行包括两个整数 xi,yi 表示第 xi 天一个顾客来充值了 yi 元 (1≤xi≤106,0≤yi≤231−1)。
输出数据
输出一行包括一个整数 ans, 表示 sqy 最多能卷走多少钱。
样例输入
5 1 5 2 5 3 5 4 5 5 5
样例输出
15
样例说明
在第五天的时候,第一个人消费4元还剩1元,第二个人消费3元还剩2元,第三个人消费2元还剩3元,第四个人消费1元还剩4元,第五个人还没有开始消费就被卷钱跑路了。
#include <stdio.h> #include <math.h> #include <string.h> #define MAX 1000010 using namespace std; long long my_min(long long a,long long b){ if(a<b) return a; else return b; } long long my_max(long long a,long long b){ if(a<b) return b; else return a; } long long in[MAX];//收益 long long out[MAX]; //花费 long long ans =0; int main(){ for (int i=0;i<1000010;i++) in[i] = out[i] = 0; long long n; scanf("%lld",&n); long long day,income; for(int i=1;i<=n;i++){ scanf("%lld%lld",&day,&income); in[day]+=income; out[day+1]--; long long leave=my_min(day+income+1,MAX); out[leave] ++; } long long cur_out=0;//当天理发人数 long long cur_in=0;//当天收益 for(int i=1;i<=MAX-10;i++){ cur_out+=out[i]; cur_in=cur_in+in[i]+cur_out; ans=my_max(ans,cur_in); } printf("%lld",ans); return 0; }
时间限制 1000 ms
内存限制 128 MB
题目描述
在这个著名的游戏中,在一个方形的盘上放置了固定数量和形状的船只,每只船却不能碰到其它的船。在这个题中,我们仅考虑船是方形的,所有的船只都是由图形组成的方形。编写程序求出该棋盘上放置的船只的总数。
输入数据
输入文件头一行由用空格隔开的两个整数 R 和 C 组成 ,1≤R,C≤1000,,1≤R,C≤1000, 这两个数分别表示游戏棋盘的行数和列数。接下来的 R 行每行包含 C 个字符,每个字符可以为“#”,也可为“.”,“#”表示船只的一部分,“.”表示水。
输出数据
为每一个段落输出一行解。如果船的位置放得正确(即棋盘上只存在相互之间不能接触的方形,如果两个“#”号上下相邻或左右相邻却分属两艘不同的船只,则称这两艘船相互接触了)。就输出一段话“There are S ships.”,S表示船只的数量。否则输出“Bad placement.”。
样例输入
6 8 .....#.# ##.....# ##.....# .......# #......# #..#...#
样例输出
There are 5 ships.
方法1
#include<iostream> using namespace std; char a[1000][1000]; int r, c; int ans = 0; int check(int i, int j) { int m,n; int x=0, y=0;//行,数 for (m = i; m < r && a[m][j] == '#'; m++) { if (j > 0 && a[m][j - 1] == '#') break; x++; } for (n = j; n < c && a[i][n] == '#'; n++) { if (i > 0 && a[i - 1][n] == '#') break; y++; } for (m = i; m < i + x; m++) { int tx = 0; for (n = j; n < c && a[m][n]=='#'; n++) { tx++; } if (tx != y) return 0; } for (n = j; n < j + y; n++) { int ty = 0; for (m = i; m < r&&a[m][n]=='#'; m++) { ty++; } if (ty != x) return 0; } for (m = i; m < i + x; m++) for (n = j; n < j + y; n++) a[m][n] = '.'; ans++; return 1; } int main() { cin >> r >> c; for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { cin >> a[i][j]; } } for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { if (a[i][j] == '#') { int flag = check(i, j); if (flag == 0) { cout << "Bad placement." << endl; return 0; } } } } cout << "There are " << ans << " ships." << endl; return 0; }
方法2
方法1的check 函数复杂度高,每一行和每一列都要进行遍历。方法2则通过寻找子结构来简化判断。可以发现在任意一个2*2的区域内如果出现了3个#, 则一定是有船相邻。方法2对check 进行优化。
#include<iostream> using namespace std; char a[1000][1000]; int r, c; int ans = 0; int check(int i, int j) { int cnt=0; if(g[x][y]=='#') cnt++; if(g[x+1][y]=='#') cnt++; if(g[x][y+1]=='#') cnt++; if(g[x+1][y+1]=='#') cnt++; return cnt==3; } int main() { cin >> r >> c; for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { cin >> a[i][j]; } } for (int i = 0; i < r; i++) { for (int j = 0; j < c; j++) { if (a[i][j] == '#') { int flag = check(i, j); if (flag == 0) { cout << "Bad placement." << endl; return 0; } } } } cout << "There are " << ans << " ships." << endl; return 0; }
方法3
方法3则是通过dfs算法,即每一次深搜的时候把与#连通的所有点改成*因为它们是同一艘船
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int r,c; char map[1010][1010]; int fx[4]={0,-1,1,0}; int fy[4]={-1,0,0,1}; int dfs(int x,int y){ map[x][y]='*'; for(int i=0;i<4;i++){ if(x+fx[i]>0 && x+fx[i]<=r && y+fy[i]>0 && y+fy[i]<=c && map[x+fx[i]][y+fy[i]]=='#') dfs(x+fx[i],y+fy[i]); } } //把与#连通的所有点改成*因为它们是同一艘船 int check(int i, int j) { int cnt=0; if(g[x][y]=='#') cnt++; if(g[x+1][y]=='#') cnt++; if(g[x][y+1]=='#') cnt++; if(g[x+1][y+1]=='#') cnt++; return cnt==3; } int main(){ scanf("%d%d",&r,&c); int i,j; for(i=1;i<=r;i++){ for(j=1;j<=c;j++){ cin>>map[i][j]; } } int s=0; for(i=1;i<=r;i++){ for(j=1;j<=c;j++){ if(i<r&&j<c&&check(i,j)==0){ printf("Bad placement."); return 0; //不合法后面就没必要继续了 } } } for(i=1;i<=r;i++){ for(j=1;j<=c;j++){ if(map[i][j]=='#'){ s++; dfs(i,j); }//因为前面已经确保了是合法的,现在只需统计船的数量 } } printf("There are %d ships.",s); return 0; }
时间限制 1000 ms
内存限制 64 MB
题目描述
在一个被分成n*n个格子的平原上,有一些格子有铁矿,两格铁矿如果相邻那么就认为他们属于同一个矿床,每个矿床都包含一个或更多个铁矿,问一共有几个矿床。
两个格子只要有公共边或公共点就算相邻。
输入数据
第一行为一个正整数n,n<=1000 接下来有n行,每行有n个字符,表示平原的对应位置有没有铁矿,*代表没有,#代表有
输出数据
矿床个数
样例输入
6 *#*### ###*#* *##*** *#**** ***### ******
样例输出
2
样例说明
最下面三块铁矿属于一个矿床,其他铁矿属于一个矿床,所以一共有两个矿床
方法1
典型的dfs, 每次搜索周围的8个点
#include<bits/stdc++.h> using namespace std; #define maxn 1005 int n; string a[maxn]; int di[] = {0, 0, 1, -1, 1, 1, -1, -1}; int dj[] = {1, -1, 0, 0, 1, -1, 1, -1}; bool inB(int i, int j){ return 1<=i&&i<=n&&1<=j&&j<=n; } void dfs(int i, int j){ a[i][j] = '*'; for(int k = 0; k<8; k++){ int ii = i+di[k], jj = j+dj[k]; if(!inB(ii, jj)||a[ii][jj]=='*') continue; dfs(ii, jj); } } int main(){ ios::sync_with_stdio(false); cin.tie(0); cin>>n; for(int i = 1; i<=n; i++){ cin>>a[i]; a[i] = " "+a[i]; } int cnt = 0; for(int i = 1; i<=n; i++){ for(int j = 1; j<=n; j++){ if(a[i][j]=='*') continue; cnt++; dfs(i, j); } } cout<<cnt; return 0; }
时间限制 1000 ms
内存限制 64 MB
题目描述
众所周知,八皇后问题是一个非常经典的算法问题,现在将题目改为在n*m的棋盘上,放min(n,m)个互不攻击的皇后,问有多少种放法。
输入数据
两个正整数n,m,n和m均不超过12
输出数据
方案数
样例输入
2 3
样例输出
2
方法1
思路:一行一行得进行摆放,用for循环来确定每一行中摆放的列数。用check判断第j行的摆放位置与1~j-1行不冲突。
#include <iostream> using namespace std; int n, m; int a[15]; int res = 0; int check(int i, int j) { int j1 = j, i1 = i, ok1 = 1; while ((j1 > 1) && ok1) { j1--; if (a[j1] == i) ok1 = 0; } j1 = j; i1 = i; while ((j1 > 1) && (i1 > 1) && ok1) { j1--; i1--; if (a[j1] == i1) ok1 = 0; } j1 = j; i1 = i; while ((j1>1) && (i1 < n) && ok1) { j1--; i1++; if (a[j1] == i1) ok1 = 0; } return ok1; } void queue(int j) { if (j > m) { res++; } else { for (int i = 1; i <= n; i++) { if (check(i, j)) { a[j] = i; queue(j + 1); } } } } int main() { cin >> n >> m; int temp; if (n < m) { temp = n; n = m; m = temp; } queue(1); cout << res; }
方法2
思路:dfs
一行一行得进行摆放,用for循环来确定每一列,由于是一行一行得摆放所以不可能同行,我们只需要标记同列,同对角线,就行,会发现主对角线一条对角线上的行列和等于同一个常数,副对角线一条对角线行列差等于一个常数,只不过会是负数,防止下标是负数我们可以进行+n。
#include<bits/stdc++.h> using namespace std; #define maxn 50 int n, m; int a[maxn][maxn]; const int bias = 25; int visc[maxn], vis1[maxn], vis2[maxn];//表示这一列,主对角线,负对角线有没有皇后 int cnt; void dfs(int i){ if(i>n){ cnt++; return; } for(int j = 1; j<=m; j++){ if(visc[j]||vis1[i+j]||vis2[i-j+bias]) continue; visc[j] = vis1[i+j] = vis2[i-j+bias] = 1; dfs(i+1); visc[j] = vis1[i+j] = vis2[i-j+bias] = 0; } } int main(){ ios::sync_with_stdio(false); cin.tie(0); cin>>n>>m; if(n>m) swap(n, m); dfs(1); cout<<cnt; return 0; }
时间限制 1000 ms
内存限制 64 MB
题目描述
给一个n个点,m条边的无向图,和一个起点s,一个终点t,问能不能从s经过一些边走到t,能走到则输出Yes,否则输出No
点的编号从1到n
输入数据
第一行为两个正整数n,m,n<=1e5,m<=1e5 接下来m行每行两个正整数t1,t2,代表t1到t2有一条无向边 最后一行为两个正整数s和t
输出数据
Yes或No
样例输入
3 2 1 2 2 3 1 3
样例输出
Yes
方法1
#include<bits/stdc++.h> using namespace std; #define maxn 100005 int n, m; vector<int> G[maxn]; int vis[maxn]; void dfs(int u){ if(vis[u]) return; vis[u] = 1; for(auto v:G[u]){ dfs(v); } } int main(){ ios::sync_with_stdio(false); cin.tie(0); cin>>n>>m; for(int i = 1; i<=m ;i++){ int u, v; cin>>u>>v; G[u].push_back(v); G[v].push_back(u); } int s, t; cin>>s>>t; dfs(s); cout<<(vis[t]?"Yes\n":"No\n"); return 0; }
时间限制 1000 ms
内存限制 128 MB
题目描述
几十年前全世界就流行一种数字扑克游戏,至今仍有人乐此不疲.在中国我们把这种游戏称为“算24点”。您作为游戏者将得到4个1-13(在扑克牌里用A代替1,J代替11,Q代替12,K代替13)之间的自然数作为操作数,而您的任务是对这4个操作数进行适当的算术运算(可以使用+、-、*、/、括号),判断运算结果是否等于24。能输出1,不能输出0。
输入数据
四个牌面值。牌面值与牌面值之间用一个空格隔开。
输出数据
输出 0 或 1 。
样例输入
3 8 10 Q
样例输出
1
样例说明
Q×(10/(8-3))=24
方法1
#include <iostream> #include <vector> using namespace std; double nums[4]; int vist[4] = {0}; bool dfs(double res) { double num; bool last = true; for (int i = 0; i < 4; ++i) { if (!vist[i]) { vist[i] = true; num = nums[i]; if (res) { if (dfs(res + num) || dfs(res - num) || dfs(num - res) || dfs(res * num) || dfs(res / num) || dfs(num / res)) { return true; } } else { if (dfs(num)) { return true; } } vist[i] = false; last = false; } } return last && res == 24; } int main() { string tmp; for (int i = 0; i < 4; ++i) { cin >> tmp; if (tmp == "A") { nums[i] = 1; } else if (tmp == "J") { nums[i] = 11; } else if (tmp == "Q") { nums[i] = 12; } else if (tmp == "K") { nums[i] = 13; } else { nums[i] = atoi(tmp.c_str()); } } if (dfs(0)) { cout << 1 << endl; } else { cout << 0 << endl; } return 0; }