永动WA题机der学习摘录

  • (一)经典内容(课堂)
    • 问题一:打印n个数的全排列,共n!个
      • Sample Input
      • Sample Output
      • 代码
    • 问题一de延伸:《五星填数》
      • Sample Output
      • 普通de代码
      • 偷鸡代码
    • 问题二:打印n个数中任意m个数的全排列
      • Sample Input
      • Sample Output
      • 代码
    • 问题三:打印n个数中任意m个数的组合
      • 代码
    • 问题四:N皇后问题(Queen.cpp)
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 代码
    • 问题五:Red and Black HDU - 1312
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 代码
    • BFS算法
    • 问题六:营救
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 代码
  • (二)有趣的题目
    • A - 双色Hanoi塔问题
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 对题目的理解
      • 代码
    • B - 简单背包问题
      • Input
      • Output
      • Sample Input
      • Sample Output
      • AC代码
    • C - 装载问题
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 理解
      • AC代码
    • D - 素数环问题
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 理解
      • AC代码
    • E - 划分整数
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 理解
      • 头铁莽夫TLE代码
      • AC代码
    • F - 最佳调度问题
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 理解
      • AC代码
    • G - 部落卫队
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 理解
      • AC代码
      • 书本题解
      • 大佬代码
    • H - 细胞有几个
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 理解
      • AC代码
    • I - 最少转弯问题
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 理解
      • AC代码
    • J - Shredding Company POJ - 1416
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 理解
      • AC代码
    • J - Find The Multiple POJ - 1426
      • Input
      • Output
      • Sample Input
      • Sample Output
      • 理解
      • AC代码
    • J - Pots POJ - 3414
      • Input
      • Output
      • Sample Input
      • Sample Output
      • AC代码
  • (三)我de感受
    • 桃某人的修炼

(一)经典内容(课堂)

问题一:打印n个数的全排列,共n!个

方法一:直接用STL的next_permutation:
这是一个大佬的对于全排列算法的分析,特别到位,直接粘过来8
https://perma.cc/79Q4-DZ5Y
方法二:用递归写程序

Sample Input

4

Sample Output

1    2    3    4
1    2    4    3
1    3    2    4
1    3    4    2
1    4    2    3
1    4    3    2
2    1    3    4
2    1    4    3
2    3    1    4
2    3    4    1
2    4    1    3
2    1    4    3
3    1    2    4
3    1    4    2
3    2    1    4
3    2    4    1
3    4    1    2
3    4    2    1
4    1    2    3
4    1    3    2
4    2    1    3
4    2    3    1
4    3    1    2
4    3    2    1

代码

#include <bits/stdc++.h>
using namespace std;
int yg[12] = {0}; //代表i号球有没有被之前的容器放过
int xl[12]; //代表n个容器里放的球的数字
int n,m;
int len = 0;
void dfs(int now){if(now == n){ //枚举到第n号容器,输出结果 for(int i = 0;i < n;i++){printf("%5d",xl[i]);}printf("\n");return;}for(int i = 1;i <= n;i++){if(yg[i] == 0){ //第i号球没被之前容器放进去过 yg[i] = 1; //第i号球已经被'now'号容器放入,不能再被后面容器放入xl[len++] = i; //now号容器存第i号球的数字dfs(now+1); //枚举到下一个容器yg[i] = 0; //讲第i号球取出,表示此球之后可以放len--; //重新枚举第now号容器里的球 }}
}int main(){cin >> n;dfs(0);return 0;
}

问题一de延伸:《五星填数》

Sample Output

12

普通de代码

#include<bits/stdc++.h>// 1 2 3|| 1 3 2 || 2 1 3|| 2 3 1|| 3 1 2|| 3 2 1
using namespace std;
int yg[12]={0};//代表i号球有没有被之前的容器放过
int xl[12];//代表n个容器里放的球的数字
int sz[100000000];
int num[15]={1,2,3,4,5,6,8,9,10,12};
int bian[5][4]={{0,1,2,3},{3,4,5,6},{6,7,1,8},{8,2,4,9},{9,5,7,0}};
int sum[5]={0};
int n,m;
int len=0;
int ans=0;
void dfs(int now){if(now==n){ //枚举到第n号容器 for(int i=0;i<5;i++){ //计算五条边的和 sum[i]=0;for(int k=0;k<4;k++)sum[i]+=xl[bian[i][k]];//xl[i]代表了第i号容器里的数字 bian[i][k] 代表了第i边里有第bian[i][k]号球 }for(int i=1;i<5;i++)//检查五条边的和是否相同 {if(sum[i]!=sum[i-1]){ //不相同答案减一,然后直接退出循环ans--;break;}}ans++;//如果五条边相同,答案加一,如果不相同,由于之前减过一次一,现在再加一就等于0.等于答案不变 return ;}for(int i=0;i<n;i++){if(yg[i]==0){ //第i号球没被之前容器放进去过 yg[i]=1;//第i号球已被‘now’号容器放入 ,不能再被后面容器放入 xl[len++]=num[i];//now号容器存第i号球的数字 dfs(now+1);//枚举到下一个容器 yg[i]=0;//讲第i号球取出,表示此球之后可以放 len--;//重新枚举第now号容器里的球 }}
}
int main(){n=10;dfs(0);printf("%d\n",ans);return 0;
}

偷鸡代码

#include <bits/stdc++.h>
using namespace std;
int main(){int sum = 0;int a[]={1,2,3,4,5,6,8,9,10,12};do{if(a[0]+a[2]+a[5]+a[8] == a[0]+a[3]+a[6]+a[9]&&a[0]+a[3]+a[6]+a[9] == a[1]+a[2]+a[3]+a[4] &&a[1]+a[2]+a[3]+a[4] == a[1]+a[5]+a[7]+a[9]&&a[1]+a[5]+a[7]+a[9] ==a[4]+a[6]+a[7]+a[8]){sum++; }}while(next_permutation(a,a+10));cout << sum / 10 << endl;return 0;
}

问题二:打印n个数中任意m个数的全排列

Sample Input

5 3

Sample Output

1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5

代码

#include <bits/stdc++.h>
using namespace std;
int n,r;
int a[25];
int b[25] = {0};void dfs(int k){ //k用于记录a添加了多少个数字 for(int i = a[k-1]+1;i <= n;i++){if(b[i] == 0){ //该数字没被访问过 a[k] = i; //添加该数字 if(k == r){ //数量达到r个输出 for(int j = 1;j <= r;j++){printf("%3d",a[j]);}printf("\n");}else{dfs(k+1); //继续添加数字 }b[i] = 0; //回溯,清空访问 }}
}
int main(){while(cin >> n >> r){memset(a,0,sizeof(a));dfs(1);}return 0;
}

问题三:打印n个数中任意m个数的组合

代码

#include <bits/stdc++.h>
using namespace std;
void print_set(int n,int k){for(int i = 0; i < (1<<n); i++)   {int num = 0, kk = i;   //num统计i中1的个数;kk用来处理i。while(kk){kk = kk&(kk-1);   //清除kk中最后一个1。num++;            //统计1的个数。}if(num == k){         //二进制数中的1有k个,符合条件。for(int j = 0; j < n; j++)if(i & (1<<j))cout << j << " ";cout << endl;}}
}
int main(){int n,k;   // n:集合中元素的总数量。k:个数为k的子集。cin>>n>>k;print_set(n,k);
}

问题四:N皇后问题(Queen.cpp)

在N*N的棋盘上放置N个皇后(n<=10)而彼此不受攻击(即在棋盘的任一行,任一列和任一对角线上不能放置2个皇后),编程求解所有的摆放方法。

Input

输入:n

Output

每行输出一种方案,每种方案顺序输出皇后所在的列号,每个数占5列。若无方案,则输出no solute!

Sample Input

4

Sample Output

2    4    1    3
3    1    4    2

代码

#include <bits/stdc++.h>
using namespace std;
int ans = 0;
int n;
int v[15] = {0};bool check(int x,int y){ //检查与已放好的是否冲突 for(int i = 0;i < x;i++){//判断对角线是否合法 if( v[i] == y || abs(v[i] - y) == abs(i-x) )return false;}return true;
}void dfs(int x){if(x == n){for(int i = 0;i < n;i++){printf("%5d",v[i]+1);}printf("\n");//ans++;}for(int y = 0;y < n;y++){if(check(x,y)){ //检查x行y列能不能放 v[x] = y; //在x行y列放一个皇后 dfs(x+1); //x行放置完毕,放x+1行 }}
}int main(){int a[] = {0,1,0,0,2,10,4,40,92,352,724,2680,14200,73712};while(cin >> n && n){if(n == 2 || n == 3) printf("no solute!\n");else{memset(v,0,sizeof(v));dfs(0);}}return 0;
}

问题五:Red and Black HDU - 1312

There is a rectangular room, covered with square tiles. Each tile is colored either red or black. A man is standing on a black tile. From a tile, he can move to one of four adjacent tiles. But he can’t move on red tiles, he can move only on black tiles.
Write a program to count the number of black tiles which he can reach by repeating the moves described above.

Input

The input consists of multiple data sets. A data set starts with a line containing two positive integers W and H; W and H are the numbers of tiles in the x- and y- directions, respectively. W and H are not more than 20.
There are H more lines in the data set, each of which includes W characters. Each character represents the color of a tile as follows.
‘.’ - a black tile
‘#’ - a red tile
‘@’ - a man on a black tile(appears exactly once in a data set)

Output

For each data set, your program should output a line which contains the number of tiles he can reach from the initial tile (including itself).

Sample Input

6 9
…#.
…#





#@…#
.#…#.
11 9
.#…
.#.#######.
.#.#…#.
.#.#.###.#.
.#.#…@#.#.
.#.#####.#.
.#…#.
.#########.

11 6
…#…#…#…
…#…#…#…
…#…#…###
…#…#…#@.
…#…#…#…
…#…#…#…
7 7
…#.#…
…#.#…
###.###
…@…
###.###
…#.#…
…#.#…
0 0

Sample Output

45
59
6
13

代码

#include <bits/stdc++.h>
using namespace std;
char c[25][25];
int ans =0;
int l,h;
int dir[4][2] = {{0,-1}, //下  {0,1}, //上{1,0}, //右{-1,0} //左
};
int check(int x,int y){if(c[x][y] != '.'||x < 0||y < 0||x >= h||y >= l)return 0;return 1;
}
void dfs(int x,int y){c[x][y] = '#';ans++;for(int i = 0;i < 4;i++){int x1 = x + dir[i][0];int y1 = y + dir[i][1];if(check(x1,y1)){dfs(x1,y1);}}
}
int main(){while(cin >> l >> h && l && h){getchar();int x,y;for(int i = 0;i < h;i++){for(int j = 0;j < l;j++){scanf("%c",&c[i][j]);if(c[i][j] == '@'){x = i;y = j;}}getchar();}ans = 0;dfs(x,y);cout << ans << endl;}return 0;
}

BFS算法

问题六:营救

铁塔尼号遇险了!他发出了求救信号。距离最近的哥伦比亚号收到了讯息,时间就是生命,必须尽快赶到那里。
通过侦测,哥伦比亚号获取了一张海洋图。这张图将海洋部分分化成n*n个比较小的单位,其中用1标明的是陆地,用0标明是海洋。船只能从一个格子,移到相邻的四个格子。
为了尽快赶到出事地点,哥伦比亚号最少需要走多远的距离。

Input

第一行为n,下面是一个n*n的0、1矩阵,表示海洋地图
最后一行为四个小于n的整数,分别表示哥伦比亚号和铁塔尼号的位置。

Output

输出哥伦比亚号到铁塔尼号的最短距离,答案精确到整数。

Sample Input

3
001
101
100
1 1 3 3

Sample Output

4

代码

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
int n,sx,sy,endx,endy;
int maze[2005][2005];struct node{int x,y; //表示当前节点在的坐标int step; //表示到达当前节点所需要的步数
};int mov[4][2]={{0,1},{1,0},{0,-1},{-1,0}};//对应节点向上、右、下、左四个方向。
int vis[2005][2005]; //对节点是否访问过进行标识,避免重复操作。int bfs(){node start;start.x = sx - 1,start.y = sy - 1;start.step = 0;memset(vis,0,sizeof(vis));queue<node> q;q.push(start); //将起点进行入队操作。 vis[start.x][start.y] = 1;while(!q.empty()){node now = q.front();q.pop(); //将当前节点进行出队。 for(int i=0;i<4;i++){ //每次循环分别对当前节点对四周节点进行访问 int nx = now.x+mov[i][0];int ny = now.y+mov[i][1];node next; //即将入队的节点if(vis[nx][ny]==0 && maze[nx][ny]==0 && nx >=0 && nx <n && ny>=0 &&ny < n){vis[nx][ny] = 1;//将已访问节点进行标注 next.x = nx;next.y = ny;next.step = now.step + 1; q.push(next); //将下一个节点进行入队操作 }if(nx==endx-1&&ny==endy-1){ //当已经到达终点时返回 return next.step; //返回从初始点到终点所需要的步数 }}       }return 0;
}int main(){cin >> n; for(int i=0;i<n;i++){for(int j=0;j<n;j++){scanf("%1d",&maze[i][j]);}}cin >> sx >> sy >> endx >> endy;int t = bfs();cout<< t <<endl;
}

(二)有趣的题目

A - 双色Hanoi塔问题

设A、B、C是3 个塔座。开始时,在塔座A 上有一叠共n 个圆盘,这些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座A 上的这一叠圆盘移到塔座B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则:
规则(1):每次只能移动1 个圆盘;
规则(2):任何时刻都不允许将较大的圆盘压在较小的圆盘之上;
规则(3):任何时刻都不允许将同色圆盘叠在一起;
规则(4):在满足移动规则(1)-(3)的前提下,可将圆盘移至A,B,C 中任一塔座上。
对于给定的正整数n,编程计算最优移动方案

Input

输入正整数n。

Output

将计算出的最优移动方案输出。每一行由一个正整数k和2个字符c1和c2组成,表示将第k个圆盘从塔座c1移到塔座c2上。2个字符之间有1个空格。

Sample Input

3

Sample Output

1 A B
2 A C
1 B C
3 A B
1 C A
2 C B
1 A B

对题目的理解

 本质上就是标准Hanoi塔问题 可以通过递归来实现递归思路:1.把A上的n-2个借助B移到C上2.把A上的两个大盘移到B3.把C上的n-2个借助B移回A上4.把B上的另一个大圆盘移到C 现在BC的底座都已经放好了,所以变成了一个新的子问题,也就是n-2个盘的双色汉诺塔所以考虑跑循环(n/2-1)次求解,上面的1,3步骤其实就各相当于一次完整的一色汉诺塔的操作,比如步骤1即相当于一色汉诺塔中把n-2个汉诺塔从a移到c,按照一色汉诺塔的递归步骤来即可

代码

#include <bits/stdc++.h>
using namespace std;
void move(int n,char a,char b,char c){if(n == 1) printf("1 %c %c\n",a,c);else{move(n-1,a,c,b);printf("%d %c %c\n",n,a,c);move(n-1,b,a,c);}
}
int main(){int n;cin >> n;move(n,'A','C','B');cout << endl;return 0;
}

B - 简单背包问题

简单的背包问题。设有一个背包,可以放入的重量为s。现有n件物品,重量分别为w1,w2…,wn,(1≤i≤n)均为正整数,从n件物品中挑选若干件,使得放入背包的重量之和正好为s。找到一组解即可。
如果找不到,输出"not found"(引号不输出)

Input

第一行是物品总件数和背包的载重量,第二行为各物品的重量。

Output

各所选物品重量(按编号从小到大顺序输出)

Sample Input

5 10
1 2 3 4 5

Sample Output

number:1 weight:1
number:4 weight:4
number:5 weight:5

AC代码

#include <bits/stdc++.h>
using namespace std;
int n,k,f = 0,b[1000];
void sum(int a[],int weight,int t){if(weight == k){ //当放入物品总量达到载重时f = 1;for(int i = 0;i < n;i++){if(b[i]==1) printf("number:%d  weight:%d\n",i+1,a[i]);}}if(f == 1) return;for(int i = t;i >= 0;i--){b[i] = 1;sum(a,weight+a[i],i-1); //寻找下一个物品放入b[i] = 0; //回溯}
}
int main(){cin >> n >> k;int a[n];for(int i = 0;i < n;i++){scanf("%d",&a[i]);}sum(a,0,n-1);if(!f) printf("not found\n");return 0;
}

C - 装载问题

有一批共n个集装箱要装上艘载重量为c的轮船,其中集装箱i的重量为wi。找出一种最优装载方案,将轮船尽可能装满,即在装载体积不受限制的情况下,将尽可能重的集装箱装上轮船。

Input

输入数据第一行有2个正整数n(n≤100)和c(c≤1000)。n是集装箱数,c是轮船的载重量。接下来的1行中有n个正整数,表示集装箱的重量。

Output

输出计算出的最大装载重量。

Sample Input

5 10
7 2 6 5 4

Sample Output

10

理解

本来jio着这道题很难来着,然后找了个大佬(紫妈)来给我讲思路,后来理解了一下,大致就是比如要求载重是10,就定义1-10不同载重的背包,然后开始存放你的物品,若物品的重量比背包剩余容量小则都放一遍。然后选择s[j]和s[j-a[i]]+a[i]里面较大的那个。就比如一组样例是
5 8
7 6 3 2 4
第一遍先放7,只有容量7,8的背包放入7。第二遍放6,后面的7,8剩余容量不足以放下6,所以6只能放进容量6的背包,接着3可以放进3,4,5,然后2可以放进2,5.这时你比较s[j] 和s[j-a[i]] + a[i]时发现6包和2包的总和比8包的7大,所以8中的载重更新为8.

AC代码

紫妈(某大佬)本来准备教我用dp写这道题的,结果我和nike(某大佬)听完dp思路后,就突然想到存一位数组直接覆盖。

#include <bits/stdc++.h>
using namespace std;
int n,w;
int a[105];int main(){cin >> n >> w;for(int i = 0;i < n;i++){scanf("%d",&a[i]);}int s[1005] = {0};for(int i = 0;i < n;i++){for(int j = w;j >= a[i];j--){s[j] = max(s[j] , s[j-a[i]] + a[i]);}}cout << s[w] << endl;return 0;
}

D - 素数环问题

素数环:从1到n(1<=n<=12)这n个数摆成一个环,要求相邻的两个数的和是一个素数。
请输出最多前5个答案以及方案总数。
如果无解,输出"no solution!"(引号不输出)

Input

输入n

Output

请输出最多前5个答案(不足5个按实际答案数输出) 以及方案总数。
如果无解,输出"no solution!"(引号不输出)

Sample Input

10

Sample Output

<1>1 2 3 4 7 6 5 8 9 10
<2>1 2 3 4 7 10 9 8 5 6
<3>1 2 3 4 9 8 5 6 7 10
<4>1 2 3 8 5 6 7 4 9 10
<5>1 2 3 8 5 6 7 10 9 4
960

理解

素数环问题:
如果 n 是奇数一定不可能
第一个数字肯定是1,所以从第二个数字开始要求找出所有的情况
利用全排列思想或者每个位置进行假定,找出所可能的排列并对其进行判断
相邻的两个数相加为素数,因要求找出素数环所以还需要进行首位的相应判断

AC代码

#include <bits/stdc++.h>
using namespace std;
int n,ans = 0;
int a[15]={0},ss[25]={0};
int v[25]={0}; //标记是否访问过
void iss(){ //判断素数 for(int i = 3;i < 2*n;i++){for(int j = 2;j < i;j++){if(i % j == 0){ss[i] = 1;break;}}}
}
void dfs(int x){if(x-1 == n && ss[a[n]+a[1]]==0){ans++;if(ans <= 5){cout << '<' << ans << '>';for(int i = 1;i <= n;i++) cout << a[i] << " ";cout << endl;}}for(int i = 1;i <= n;i++){if(!v[i]){if(x == 1 || x >= 2 && ss[i+a[x-1]]==0){a[x] = i;v[i] = 1; //标记访问 dfs(x+1);v[i] = 0; //清空状态 }}}
}
int main(){cin >> n;if(n == 1){cout << "no solution!" << endl;return 0;}iss();dfs(1);if(ans) cout << ans << endl;else cout << "no solution!" << endl;return 0;
}

E - 划分整数

将整数n分成k份,且每份不能为空,任意两种分法不能相同(不考虑顺序)。例如:n=7,k=3,下面三种分法被认为是相同的。
1,1,5; 1,5,1; 5,1,1;
问有多少种不同的分法。

Input

输入n,k (6<n≤200,2≤k≤6)

Output

输出一个整数,即不同的分法。

Sample Input

7 3

Sample Output

4

理解

 这道题!!!我超时了五次!起先觉得递归不会超时,无奈题不让我偷鸡,撞不过撞不过。然后换了dfs来写,然鹅我还是超时了!因为没有判断条件剪枝!一把辛酸泪

头铁莽夫TLE代码

#include <bits/stdc++.h>
using namespace std;int s(int a,int b){if(a == 0 || b == 1 || a == 1) return 1;else return s(a,b-1) + s(a-b,b);
}
int main(){int n,k;cin >> n >> k;n -= k;cout << s(n,k) << endl;
}

AC代码

#include <bits/stdc++.h>
using namespace std;
int n,k,ans = 0;
void dfs(int x,int t,int max){if(t == k&&x == n) ans++;else if(t != k && x < n){for(int i = max;i > 0;i--){dfs(x+i,t+1,i);}}else return;
}
int main(){cin >> n >> k;if(k == 1) cout << 1 << endl;else{dfs(0,0,n-1);cout << ans << endl;}
}

F - 最佳调度问题

假设有n个任务由k个可并行工作的机器完成。完成任务i需要的时间为ti。试设计一个算法找出完成这n个任务的最佳调度,使得完成全部任务的时间最早。
    对任意给定的整数n和k,以及完成任务i需要的时间为ti,i=1~n。编程计算完成这n个任务的最佳调度。

Input

给出输入数据。第一行有2 个正整数n和k。第2 行的n个正整数是完成n个任务需要的时间。

Output

将计算出的完成全部任务的最早时间输出

Sample Input

7 3
2 14 4 16 6 5 3

Sample Output

17

理解

 这题是台风假期补的题。也是卡了我很久,还是令人头疼的tle问题!!自定义一个cmp来排序从大到小减少循环,然后记得剪枝!

AC代码

#include <bits/stdc++.h>
using namespace std;
int n,k,ans = 100000,p[7],a[25];
bool cmp(int a,int b){return a > b;
}
void dfs(int d,int t){if(t >= ans) return;if(d == n + 1){if(ans > t) ans = t;return;}for(int j = 1;j <= k;j++){if(p[j]+a[d] <= ans){p[j] += a[d];dfs(d+1,max(t,p[j]));p[j] -= a[d];}}return;
}
int main(){cin >> n >> k;for(int i = 1;i <= n;i++){cin >> a[i];}sort(a+1,a+n+1);dfs(1,0);cout << ans << endl;return 0;
}

G - 部落卫队

原始部落byteland中的居民们为了争夺有限的资源,经常发生冲突。几乎每个居民都有他的仇敌。部落酋长为了组织一支保卫部落的队伍,希望从部落的居民中选出最多的居民入伍,并保证队伍中任何2 个人都不是仇敌。给定byteland部落中居民间的仇敌关系,编程计算组成部落卫队的最佳方案。

Input

第1行有2个正整数n和m,表示byteland部落中有n个居民,居民间有m个仇敌关系。居民编号为1,2,…,n。接下来的m行中,每行有2个正整数u和v,表示居民u与居民v是仇敌。

Output

第1行是部落卫队的顶人数;文件的第2行是卫队组成x i,1≤i≤n,xi =0 表示居民i不在卫队中,xi=1表示居民i在卫队中。
otherwise.

Sample Input

7 10
1 2
1 4
2 4
2 3
2 5
2 6
3 5
3 6
4 5
5 6

Sample Output

3
1 0 1 0 0 0 1

理解

 这道题其实不难but我杞县康到了趣学算法上的题解,后面会贴出来。个人认为写的有点麻烦,还是自己写的代码易懂(小声)

AC代码

#include <bits/stdc++.h>
using namespace std;int main(){int t;cin >> t;while(t--){int n;cin >> n;set<pair<int,int> > s;int a,b;int f = 1;double sum = 0;for(int i = 0;i < n;i++){cin >> a >> b;sum += a;pair<int,int> p = make_pair(a,b);s.insert(p);}sum = sum /(1.0*n) * 2.0;set<pair<int,int> >::iterator it;for(it = s.begin();it != s.end();it++){if(s.find(make_pair(sum-(it -> first),it -> second))==s.end()){f = 0;break;}}if(f) cout << "YES" << endl;else cout << "NO" << endl;}return 0;
}

书本题解



大佬代码

#include <iostream>
#include <string.h>
using namespace std;
const int N = 100;
int a[N][N]; //图用邻接矩阵表示
bool x[N]; //是否将第 i 个结点加入团中
bool bestx[N]; //记录最优解
int bestn; //记录最优值
int cn; //当前已放入团中的结点数量
int n,m; //n 为图中结点数,m 为图中边数
bool Place(int t){ //判断是否可以把结点 t 加入团中bool ok=true;for(int j=1;j<t; j++){ //结点 t 与前 t-1 个结点中被选中的结点是否相连if(x[j]&&a[t][j]==0){ //x[j]表示j 是被选中的结点,a[t][j]==0 表示t 和j 没有边相连ok = false;break;}}return ok;
}
void Backtrack(int t){if(t>n){ //到达叶结点for(int i=1; i<=n; i++)bestx[i]=x[i];bestn=cn;return ;} if(Place(t)){ //满足约束条件,进入左子树,即把结点 t 加入团中x[t]=1;cn++;Backtrack(t+1);cn--;}if(cn+n-t>bestn){ //满足限界条件,进入右子树x[t] = 0;Backtrack(t + 1);}
}
int main(){int u, v;cout << "请输入部落的人数 n(结点数):";cin >> n;cout << "请输入人与人的友好关系数(边数):";cin >> m;memset(a,0,sizeof(a));//邻接矩阵里面的数据初始化为0,需要引入#include <string.h>cout << "请依次输入有友好关系的两个人(有边相连的两个结点 u 和 v)用空格分开:";for(int i=1;i<=m;i++){cin>>u>>v;a[u][v]=a[v][u]=1;}bestn=0;cn=0;Backtrack(1);cout<<"国王护卫队的最大人数为:"<<bestn<<endl;cout<<"国王护卫队的成员为:";for(int i=1;i<=n;i++)if(bestx[i])cout<<i<<" ";return 0;
}

输入
请输入部落的人数 n(结点数):5
请输入人与人的友好关系数(边数):8
请依次输入有友好关系的两个人(有边相连的两个结点 u 和 v)用空格分开:
1 2
1 3
1 4
1 5
2 3
3 4
3 5
4 5
输出
国王护卫队的最大人数为:4
国王护卫队的成员为:1 3 4 5

H - 细胞有几个

一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。
如: 阵列 4 10
0234500067
1034560500
2045600671
0000000089
有4个细胞。

Input

输入有多行,第一行表示矩阵阵列的行数m和列数n(m<=70,n<=70);
接下来的m行n列为0-9等10个数字构成的矩阵。

Output

输出细胞个数。

Sample Input

4 10
0234500067
1034560500
2045600671
0000000089

Sample Output

4

理解

 这道题要求细胞附近必须是细胞,求连续成片的最多的细胞数。其实一上手本来以为这题和之前的涂色求面积最大类似,仔细一看又不太相同。问过大佬后,发现可以在输入时就预处理好改点是不是细胞,存成只剩1和0的形式,然后判断该细胞周围连成的一片面积有多少细胞。

AC代码

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
int m,n;
int v[105][105]={0}; //标记该点是否是细胞
int mov[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
int num = 0;
struct point{int x,y;
};
void bfs(int x,int y){num++;point start;start.x = x,start.y = y;queue<point> q;q.push(start);v[start.x][start.y] = 0;while(!q.empty()){point t = q.front();q.pop();for(int i = 0;i < 4;i++){int nx = t.x+mov[i][0];int ny = t.y+mov[i][1];point next;if(v[nx][ny]&& nx >=0 && nx <n && ny>=0 &&ny < n){v[nx][ny] = 0;next.x = nx;next.y = ny;q.push(next);}}}
}int main(){cin >> m >> n; for(int i=0;i<m;i++){string s;cin >> s;for(int j=0;j<s.size();j++){if(s[j] != '0') v[i][j] = 1;}}for(int i=0;i<m;i++){for(int j = 0;j < n;j++){if(v[i][j]){bfs(i,j);}}}cout << num << endl;return 0;
}

I - 最少转弯问题

给出一张地图,这张地图被分为n×m(n,m<=100)个方块,任何一个方块不是平地就是高山。平地可以通过,高山则不能。现在你处在地图的(x1,y1)这块平地,问:你至少需要拐几个弯才能到达目的地(x2,y2)?你只能沿着水平和垂直方向的平地上行进,拐弯次数就等于行进方向的改变(从水平到垂直或从垂直到水平)的次数。例如:如图,最少的拐弯次数为5。

Input

第1行:n m
第2至n+1行:整个地图地形描述(0:空地;1:高山),
如(图)第2行地形描述为:1 0 0 0 0 1 0
第3行地形描述为:0 0 1 0 1 0 0
……
第n+2行:x1 y1 x2 y2 (分别为起点、终点坐标)

Output

输出s (即最少的拐弯次数)

Sample Input

5 7
1 0 0 0 0 1 0
0 0 1 0 1 0 0
0 0 0 0 1 0 1
0 1 1 0 0 0 0
0 0 0 0 1 1 0
1 3 1 7

Sample Output

5

理解

 这题一直想不到思路!然后去康了题解!神仙做法存下前后两个坐标,由此来判断是否转弯!

AC代码

#include <bits/stdc++.h>
using namespace std;
int n,m,sx,sy,endx,endy;
int a[105][105];
int mov[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
struct node{int x,y; //表示当前节点在的坐标int oldx,oldy; //表示前一个坐标int ans; //转弯次数
};
queue<node> q;
int bfs(){node p;p.x = sx,p.y = sy;p.oldx = sx,p.oldy = sy;p.ans = 0;q.push(p);while(!q.empty()){p = q.front();q.pop();if(p.x == endx && p.y == endy){ return p.ans;break;}node next;for(int i=0;i<4;i++){ //每次循环分别对当前节点对四周节点进行访问 next.x = p.x + mov[i][0];next.y = p.y + mov[i][1];if(next.x >= 1 && next.x <= n && next.y >= 1 &&next.y <= m &&(!a[next.x][next.y])){if(next.x!= p.oldx && next.y!=p.oldy){next.ans= p.ans + 1;}else{next.ans = p.ans;}next.oldx = p.x;next.oldy = p.y;q.push(next);}}       }return 0;
}int main(){cin >> n >> m;for(int i = 1;i <= n;i++){for(int j = 1;j <= m;j++){cin >> a[i][j];}}cin >> sx >> sy >> endx >> endy;int t = bfs();cout << t << endl;return 0;
}

J - Shredding Company POJ - 1416

You have just been put in charge of developing a new shredder for the Shredding Company Although a “normal” shredder would just shred sheets of paper into little pieces so that the contents would become unreadable, this new shredder needs to have the following unusual basic characteristics.
1.The shredder takes as input a target number and a sheet of paper with a number written on it.
2.It shreds (or cuts) the sheet into pieces each of which has one or more digits on it.
3.The sum of the numbers written on each piece is the closest possible number to the target number, without going over it.
For example, suppose that the target number is 50, and the sheet of paper has the number 12346. The shredder would cut the sheet into four pieces, where one piece has 1, another has 2, the third has 34, and the fourth has 6. This is because their sum 43 (= 1 + 2 + 34 + 6) is closest to the target number 50 of all possible combinations without going over 50. For example, a combination where the pieces are 1, 23, 4, and 6 is not valid, because the sum of this combination 34 (= 1 + 23 + 4 + 6) is less than the above combination’s 43. The combination of 12, 34, and 6 is not valid either, because the sum 52 (= 12 + 34 + 6) is greater than the target number of 50.

Figure 1. Shredding a sheet of paper having the number 12346 when the target number is 50
There are also three special rules :
1.If the target number is the same as the number on the sheet of paper, then the paper is not cut.
For example, if the target number is 100 and the number on the sheet of paper is also 100, then
the paper is not cut.
2.If it is not possible to make any combination whose sum is less than or equal to the target number, then error is printed on a display. For example, if the target number is 1 and the number on the sheet of paper is 123, it is not possible to make any valid combination, as the combination with the smallest possible sum is 1, 2, 3. The sum for this combination is 6, which is greater than the target number, and thus error is printed.
3.If there is more than one possible combination where the sum is closest to the target number without going over it, then rejected is printed on a display. For example, if the target number is 15, and the number on the sheet of paper is 111, then there are two possible combinations with the highest possible sum of 12: (a) 1 and 11 and (b) 11 and 1; thus rejected is printed. In order to develop such a shredder, you have decided to first make a simple program that would simulate the above characteristics and rules. Given two numbers, where the first is the target number and the second is the number on the sheet of paper to be shredded, you need to figure out how the shredder should “cut up” the second number.

Input

The input consists of several test cases, each on one line, as follows :
tl num1
t2 num2

tn numn
0 0
Each test case consists of the following two positive integers, which are separated by one space : (1) the first integer (ti above) is the target number, (2) the second integer (numi above) is the number that is on the paper to be shredded.
Neither integers may have a 0 as the first digit, e.g., 123 is allowed but 0123 is not. You may assume that both integers are at most 6 digits in length. A line consisting of two zeros signals the end of the input.

Output

For each test case in the input, the corresponding output takes one of the following three types :
sum part1 part2 …
rejected
error
In the first type, partj and sum have the following meaning :
1.Each partj is a number on one piece of shredded paper. The order of partj corresponds to the order of the original digits on the sheet of paper.
2.sum is the sum of the numbers after being shredded, i.e., sum = part1 + part2 +…
Each number should be separated by one space.
The message error is printed if it is not possible to make any combination, and rejected if there is
more than one possible combination.
No extra characters including spaces are allowed at the beginning of each line, nor at the end of each line.

Sample Input

50 12346
376 144139
927438 927438
18 3312
9 3142
25 1299
111 33333
103 862150
6 1104
0 0

Sample Output

43 1 2 34 6
283 144 139
927438 927438
18 3 3 12
error
21 1 2 9 9
rejected
103 86 2 15 0
rejected

理解

这题要求给你一串数字让你对它进行分割,使得分割出来的每一个数字相加后能成为最接近所给数字并且不大于它的结果。

AC代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int d[1000000];
int maxn,ans,v[10],vt[10],len,t;
char num[10];
void dfs(int x,int m,int c){int f,y;if(x > len - 1){f = 1;for(int i = 0;i < c;i++){if(vt[i] != v[i]) f = 0;}if(maxn < m){maxn = m;ans = c;for(int i = 0;i < c;i++) vt[i] = v[i];}if(f == 0){d[m]++;}return;}y = 0;for(int i = x;i < len;i++){y = y * 10 + (num[i] - '0');if(y + m <= t){v[c] = y;dfs(i+1,y+m,c+1);}else break;}
}
int main(){while(scanf("%d %s",&t,&num)){memset(v,0,sizeof(v));memset(vt,0,sizeof(vt));memset(d,0,sizeof(d));len = strlen(num);if(t == 0 && len == 1 && num[0] == '0') break;int s = 0;for(int i = 0;i < len;i++){s += num[i] -'0';}if(s > t){cout << "error" << endl;continue;}maxn = 0,ans = 0;dfs(0,0,0);if(d[maxn] != 1) cout << "rejected" << endl;else{cout << maxn;for(int i = 0;i < ans;i++) cout << " " << vt[i];cout << endl;}}return 0;
}

J - Find The Multiple POJ - 1426

Given a positive integer n, write a program to find out a nonzero multiple m of n whose decimal representation contains only the digits 0 and 1. You may assume that n is not greater than 200 and there is a corresponding m containing no more than 100 decimal digits.

Input

The input file may contain multiple test cases. Each line contains a value of n (1 <= n <= 200). A line containing a zero terminates the input.

Output

For each value of n in the input print a line containing the corresponding value of m. The decimal representation of m must not contain more than 100 digits. If there are multiple solutions for a given value of n, any one of them is acceptable.

Sample Input

2
6
19
0

Sample Output

10
100100100100100100
111111111111111111

理解

 学长交给我们偷鸡写法!!!嘻嘻,偷懒小能手既然他要求二进制,那我们就自己造二进制嘻嘻

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,f;void dfs(long long x,int ans){if(f || ans > 18) return;if(x % n == 0){f = 1;printf("%lld\n",x);}dfs(x*10,ans+1);dfs(x*10+1,ans+1);
}
int main(){while(cin >> n && n){f = 0;dfs(1,0);}return 0;
}

J - Pots POJ - 3414

You are given two pots, having the volume of A and B liters respectively. The following operations can be performed:
FILL(i) fill the pot i (1 ≤ i ≤ 2) from the tap;
DROP(i) empty the pot i to the drain;
POUR(i,j) pour from pot i to pot j; after this operation either the pot j is full (and there may be some water left in the pot i), or the pot i is empty (and all its contents have been moved to the pot j).
Write a program to find the shortest possible sequence of these operations that will yield exactly C liters of water in one of the pots.

Input

On the first and only line are the numbers A, B, and C. These are all integers in the range from 1 to 100 and C≤max(A,B).

Output

The first line of the output must contain the length of the sequence of operations K. The following K lines must each describe one operation. If there are several sequences of minimal length, output any one of them. If the desired result can’t be achieved, the first and only line of the file must contain the word ‘impossible’.

Sample Input

3 5 4

Sample Output

6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)

AC代码

#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int a,b,c,f;
int v[205][205];
int choice[10000];
int p[10000];
void print(int x){if(p[x]==-1)return;print(p[x]);if(choice[x]==1) printf("FILL(1)\n");else if(choice[x]==2) printf("FILL(2)\n");else if(choice[x]==3) printf("DROP(1)\n");else if(choice[x]==4) printf("DROP(2)\n");else if(choice[x]==5) printf("POUR(2,1)\n");else if(choice[x]==6) printf("POUR(1,2)\n");
}
int check(int x,int y){if(x<0||y<0||x>a||y>b||v[x][y]) return 1;return 0;
}
struct node{int x,y; // a,b两瓶的水量int ans; //操作步数 int id; //六种不同的操作
};
node now;
int bfs(){node next;queue<node> q;now.x = 0,now.y = 0;now.ans = 0,now.id = 0;p[0]=-1;v[now.x][now.y] = 1;q.push(now);int cnt=0;while(!q.empty()){now = q.front();q.pop();if(now.x == c || now.y == c){return now.ans;}//倒满a next.x = a;next.y = now.y;if(!check(next.x,next.y)){cnt++;next.id = cnt;next.ans = now.ans + 1;v[next.x][next.y] = 1;q.push(next);p[cnt] = now.id;choice[cnt] = 1;}//倒满bnext.x = now.x;next.y = b;if(!check(next.x,next.y)){cnt++;next.id = cnt;next.ans = now.ans + 1;v[next.x][next.y] = 1;q.push(next);p[cnt] = now.id;choice[cnt] = 2;}//倒空a next.x = 0;next.y = now.y;if(!check(next.x,next.y)){cnt++;next.id = cnt;next.ans = now.ans + 1;v[next.x][next.y] = 1;q.push(next);p[cnt] = now.id;choice[cnt] = 3;}//倒空bnext.x = now.x;next.y = 0;if(!check(next.x,next.y)){cnt++;next.id = cnt;next.ans = now.ans + 1;v[next.x][next.y] = 1;q.push(next);p[cnt] = now.id;choice[cnt] = 4;}//b->a ,a不满if(now.x+now.y <= a && now.y!=0){next.x = now.x+now.y;next.y = 0;if(!check(next.x,next.y)){cnt++;next.id = cnt;next.ans = now.ans + 1;v[next.x][next.y] = 1;q.push(next);p[cnt] = now.id;choice[cnt] = 5;}}//b->a,a溢出if(now.x+now.y > a && now.y!=0){next.x = a;next.y = now.y-(a-now.x);if(!check(next.x,next.y)){cnt++;next.id = cnt;next.ans = now.ans + 1;v[next.x][next.y] = 1;q.push(next);p[cnt] = now.id;choice[cnt] = 5;}}//a->b ,b不满if(now.x+now.y <= b && now.x!=0){next.x = 0;next.y = now.x+now.y;if(!check(next.x,next.y)){cnt++;next.id = cnt;next.ans = now.ans + 1;v[next.x][next.y] = 1;q.push(next);p[cnt] = now.id;choice[cnt] = 6;}}//a->b,b溢出if(now.x+now.y > b && now.x!=0){next.x = now.x-(b-now.y);next.y = b;if(!check(next.x,next.y)){cnt++;next.id = cnt;next.ans = now.ans + 1;v[next.x][next.y] = 1;q.push(next);p[cnt] = now.id;choice[cnt] = 6;}}}return -1;
}
int main(){cin >> a >> b >> c;f = 1;memset(v,0,sizeof(v));int u = bfs();if(u == -1) cout << "impossible" << endl;else{printf("%d\n",now.ans);print(now.id);}return 0;
}

(三)我de感受

桃某人的修炼

这周是疯狂TLE的5201大型自闭现场
    老柴出差了,学长讲课,印象最深的竟然是一位学长为了让我们弄懂如何走迷宫,用忍术讲题,在线分身(笑)
    dfs和bfs一生之敌(我的敌人好多),学起来还是有点困难的,从只会写讲过的题到会套模板再到能自己写并找错真是一个艰辛的过程。
       我和我对自己的期望还差得远。
       这周布置的题集,acm能写完大部分,vj还空缺着很多题,期盼着自己有时间补一补。上周的洛谷5题flag倒了,或许这周能完成。

令人头秃的集训第三周学习记录(练习题+感悟)相关推荐

  1. django实现证件照换底色后端和小程序(第三周学习记录)

    第三周学习记录 继续上周的django后台搭建,经过讨论选择不使用mysql数据库存储用户上传证件照信息,直接通过base64转码的形式在后台处理并返回前端直接通过数据流预览并实现图片下载 一.后端获 ...

  2. 循迹追踪令人头秃的Crash,十倍程序员的Debug日常(2)

    作者|陶建辉 原文首发于: 循迹追踪令人头秃的Crash 我们写 C 程序,经常碰到 Crash,绝大部分情况下都是空指针或野指针造成,从 call stack 来看,一般很容易找出问题.但是有一类 ...

  3. 令人头秃的:你的主机中的软件中止了一个已建立的连接

    此文章来源于项目官方公众号:"AirtestProject" 版权声明:允许转载,但转载必须保留原链接:请勿用作商业或者非法用途 1. 前言 最近在答疑群中,经常看到同学们遇到 你 ...

  4. 双指针算法何时加减令人头秃怎么办

    用双指针去做循环的时候,什么时候该把指针加一,何时该减一,实在是令人头秃. 今天分享一个简单的小技巧--枚举法. 举个例子: 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持 ...

  5. 20145240 《信息安全系统设计基础》第三周学习总结

    20145240 <信息安全系统设计基础>第三周学习总结 教材学习内容总结 p20 三种数字: 无符号数:基于传统二进制表示法,表示大于或者等于零的数字. 补码:表示有符号整数的最常见方式 ...

  6. 学号 20172326 《程序设计与数据结构》第三周学习总结

    学号 20172326 <程序设计与数据结构>第三周学习总结 教材学习内容总结 队列是先进先出的数据结构(FIFO)与栈不同,队列的两端可分别进行操作 first与front相同,返回首段 ...

  7. 20165206 2017-2018-2 《Java程序设计》第三周学习总结

    20165206 2017-2018-2 <Java程序设计>第三周学习总结 教材学习内容总结 类:class是关键字,用来定义类. 类声明:例如class People. 对象的声明:类 ...

  8. 20155117 王震宇 2006-2007-2 《Java程序设计》第三周学习总结

    20155117 王震宇 2006-2007-2 <Java程序设计>第三周学习总结 教材学习内容总结 在JAVA程序编写中,常常要用到对象(Object),要产生对象首先要定义类(Cla ...

  9. 2017-2018-1 20155338 《信息安全系统设计基础》 第三周学习总结

    2017-2018-1 20155338 <信息安全系统设计基础>第三周学习总结 教材学习内容总结 一.三种重要的数字表示 (1)无符号数.有符号数.浮点数 无符号编码是基于传统的二进制表 ...

最新文章

  1. 一文尽览5G全产业链及新机遇
  2. 【转】adobe acrobat pro修改pdf文字
  3. Aix /etc/hosts.equiv 文件的用途及用法
  4. aws java mysql_AWS Serverless部署java api(RDS for MySQL篇)
  5. pgsql的存储过程调用mysql_PostgreSQL存储过程循环调用方式
  6. python模块与包
  7. php时间格式函数,PHP函数之日期时间函数date()使用详解_php基础_脚本
  8. c语言递归求差分方程,如何使这个简单的递推关系(差分方程)尾递归?
  9. Linux浏览器libgtk-3,终于把WebKit(基于GTK)移植到ARM上
  10. collins词典第八版mdx_英语词典选择
  11. tomcat source code in eclipse
  12. 怎么取消wps云服务器_关闭手机版wps云服务器
  13. 前端导出 pdf 分页带表头,导出pdf 不分页
  14. 为什么选择语音验证码?
  15. 2015年3月1日起停止提供4年或5年SSL证书
  16. 【Tensorflow】报错:FailedPreconditionError: Attempting to use uninitialized value keep_prob_7
  17. 理解AsyncTask
  18. Python和R交互使用
  19. 计算机绘图说课视频,说课稿认识画图软件
  20. mysql 通过客户端执行now()函数,时差为8小时

热门文章

  1. 燕东微在科创板上市:市值263亿元,北京电控、亦庄国投等为股东
  2. 服务器端编程心得(七)——开源一款即时通讯软件的源码
  3. matplotlib绘制三维图
  4. 遗传算法之扇贝的进化(python代码实现)
  5. 使用JavaScript创建SVG矢量图Code128编码
  6. 微型计算机的型号是奔四800,第1章 微型计算机基础知识
  7. 教你win10更新失败怎么解决,win10系统更新失败怎么办
  8. java中构造函数-静态代码块-代码块的执行顺序
  9. sql2000 指定的服务器不存在,SQL Server 2000服务无法启动,提示“系统找不到指定的文件”解决方法及sp4安装不上...
  10. 如何把很多照片拼成一张照片_怎样用手机将多张照片拼成一张组合图