1 最佳调度问题
假设有n(n<=20)个任务由k(k<=20)个可并行工作的机器完成。完成任务i需要的时间为ti。 试设计一个算法,对任意给定的整数n和k,以及完成任务i 需要的时间为ti ,i=1~n。计算完成这n个任务的最佳调度,使得完成全部任务的时间最早。
输入格式:
输入数据的第一行有2 个正整数n和k。第2 行的n个正整数是完成n个任务需要的时间。
输出格式:
将计算出的完成全部任务的最早时间输出到屏幕。
输入样例:
在这里给出一组输入。例如:
7 3
2 14 4 16 6 5 3
输出样例:
在这里给出相应的输出。例如:
17
import java.util.*;
public class Main {
static int n, k;
static int[] machine; //机器加入的任务用时
static int[] task; //每个任务完成需要的时间
static int minTime;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
k = sc.nextInt();
task = new int[n];
machine = new int[k];
for(int i=0;i<n;i++) {
task[i] = sc.nextInt();
minTime+=task[i];
}
recursion(0);
System.out.println(minTime);
}
public static void recursion(int i) {
if(i<n) {
for(int j=0;j<k;j++) {
//由第j台机器完成第i项任务
machine[j]+=task[i];
if(machine[j]<minTime) { //判断是否已经大于了现有的最小时间
recursion(i+1);
}
//第j机器不完成第i项任务
machine[j]-=task[i];
}
}
else {
int nowMaxTime = 0; //所有任务完成的最短时间取决于最后一个任务完成的机器的用时
for(int j=0;j<k;j++) {
nowMaxTime = Math.max(nowMaxTime, machine[j]);
}
minTime = Math.min(minTime, nowMaxTime); //保证用时的最短
}
}
}
2 八皇后问题
在国际象棋中,皇后是最厉害的棋子,可以横走、直走,还可以斜走。棋手马克斯·贝瑟尔 1848 年提出著名的八皇后问题:即在 8 × 8 的棋盘上摆放八个皇后,使其不能互相攻击 —— 即任意两个皇后都不能处于同一行、同一列或同一条斜线上。例如:
现在我们把棋盘扩展到 n×n 的棋盘上摆放 n 个皇后,请问该怎么摆?
请编写程序,输入正整数 n,输出全部摆法(棋盘格子空白处显示句点“.”,皇后处显示字母“Q”,每两个字符之间空一格)。
输入格式
正整数 n(n>0)
输出格式
若问题有解,则输出全部摆法(每两种摆法之间空一行)。
若问题无解,则输出 None。
要求:试探的顺序按从上到下逐行进行,其中每一行按从左到右的逐格进行,请参看输出样例2。
输入样例1
3
输出样例1
None
输入样例2
6
输出样例2
. Q . . . .
. . . Q . .
. . . . . Q
Q . . . . .
. . Q . . .
. . . . Q .
. . Q . . .
. . . . . Q
. Q . . . .
. . . . Q .
Q . . . . .
. . . Q . .
. . . Q . .
Q . . . . .
. . . . Q .
. Q . . . .
. . . . . Q
. . Q . . .
. . . . Q .
. . Q . . .
Q . . . . .
. . . . . Q
. . . Q . .
. Q . . . .
import java.util.*;
class Q { //皇后类
int x,y;
public Q(int x, int y) {
this.x = x;
this.y = y;
}
}
public class Main {
static int n;
static int[][] chressBoard;
static ArrayList<Q> list = new ArrayList<Q>(); //用于存放每个皇后的位置
static boolean Flag = true;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
chressBoard = new int[n][n];
recursion(0,1, chressBoard);
if(Flag)
System.out.println("None");
}
public static void recursion(int x, int count, int[][] chressBoard) {
for(int y=0;y<n;y++) {
if(chressBoard[x][y] == 0) {
if(list.isEmpty()) {
chressBoard[x][y] = 1;//标记皇后的位置为1。
list.add(new Q(x,y));
}
else {
boolean flag = true;
for(int i=0,size=list.size();i<size;i++) {
Q tmp = list.get(i);
//判断任意两个皇后都不能处于同一行、同一列或同一条斜线上
if(tmp.x==x || tmp.y==y || (Math.abs(tmp.x-x)==Math.abs(tmp.y-y)))
flag = false;
}
if(flag) {
chressBoard[x][y] = 1; //标记皇后的位置为1。
list.add(new Q(x,y));
}
else
continue;
}
if(x<n-1) {
recursion(x+1, count+1, chressBoard);
}
if(count == n) { //存在解
Flag = false;
//将结果输出
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
if(chressBoard[i][j]==1) {
if(j<n-1)
System.out.print("Q ");
else
System.out.print("Q");
}
else {
if(j<n-1)
System.out.print(". ");
else
System.out.print(".");
}
}
System.out.println();
}
System.out.println();
}
chressBoard[x][y] = 0; //还原对皇后位置在图中的标记为0
list.remove(list.size()-1); //在list中删除对皇后的标记
}
}
}
}
3 0-1背包
给定n(n<=100)种物品和一个背包。物品i的重量是wi,价值为vi,背包的容量为C(C<=1000)。问:应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有两个选择:装入或不装入。不能将物品i装入多次,也不能只装入部分物品i。
输入格式:
共有n+1行输入: 第一行为n值和c值,表示n件物品和背包容量c; 接下来的n行,每行有两个数据,分别表示第i(1≤i≤n)件物品的重量和价值。
输出格式:
输出装入背包中物品的最大总价值。
输入样例:
在这里给出一组输入。例如:
5 10
2 6
2 3
6 5
5 4
4 6
输出样例:
在这里给出相应的输出。例如:
15
import java.util.Scanner;
public class Main {
static Scanner in=new Scanner(System.in);
public static int ZeroOnePack2(int C,int N,int[] weight,int[] value){
//动态规划
int[] dp = new int[C+1];
for(int i=1;i<N+1;i++){
//逆序实现
for(int j=C;j>=weight[i-1];j--){
dp[j] = Math.max(dp[j-weight[i-1]]+value[i-1],dp[j]);
}
}
return dp[C];
}
public static void main(String[] args) {
int n = in.nextInt();//n件物品
int c = in.nextInt();//背包容量
int[] weight = new int[n];
int[] value = new int [n];
for(int i=0;i<n;i++) {
weight[i] = in.nextInt();
value[i] = in.nextInt();
}
System.out.println(ZeroOnePack2(c,n,weight,value));
}
}
4 整数拆分
将一个正整数拆分成若干个正整数的和。
输入格式:
一个正整数n
输出格式:
若干行,每行一个等式(每个数或者等号间都有一个空格,第一个数前没有空格,最后一个数后面没有空格,数与数之间要求非降序排列)。最后一行给出解的总个数
输入样例:
在这里给出一组输入。例如:
4
输出样例:
在这里给出相应的输出。例如:
4 = 1 + 1 + 1 + 1
4 = 1 + 1 + 2
4 = 1 + 3
4 = 2 + 2
4
import java.util.*;
class Composition extends ArrayList<Integer> {
@Override
public boolean equals(Object other) {
Composition comp = (Composition) other;
Collections.sort(this);
Collections.sort(comp);
if (this.isEmpty() || comp.isEmpty() || this.size() != comp.size())
return false;
for (int i = 0; i < this.size(); i++)
if (this.get(i) != comp.get(i))
return false;
return true;
}
@Override
public int hashCode() {
return 0;
}
}
public class Main{
static int n ;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
System.out.print(toStr(calc(n)));
}
public static Set<Composition> calc(int n) {
Set<Composition> possibility = new HashSet<Composition>();
Composition composition = new Composition();
switch (n) {
case 1:
composition.add(1);
possibility.add(composition);
return possibility;
case 2:
composition.add(1);
composition.add(1);
possibility.add(composition);
return possibility;
default:
for (int i = 1; i <= n / 2; i++) {
composition = new Composition();
composition.add(i);
composition.add(n - i);
possibility.add(composition);
if (i <= n - i) {
Set<Composition> partial_pos = calc(n - i);
for (Composition pos : partial_pos) {
pos.add(i);
possibility.add(pos);
}
}
}
return possibility;
}
}
public static String toStr(Set<Composition> possibility) {
String str = new String();
for (Composition pos : possibility)
str += toStr(pos);
str += possibility.size();
return str;
}
public static String toStr(Composition composition) {
String str = n+" = "+composition.get(0) + "";
for (int i = 1; i < composition.size(); i++)
str += (" + " + composition.get(i));
str += "\n";
return str;
}
}
5 666
小明有一张m*n的好习惯记录卡,记录每一天的好习惯目标达成度(数字0-9表示)。某天目标完成达成,就在当天的格子里写上数字6,目标没有完全达成就写上一个小于6的数字(0-5),目标超额完成就写上一个大于6的数字(7-9)。记录卡上如果能找到一条长度为3的路径并且路径上的三个数字都大于等于6(这里的路径是指从某个格子出发,可以向左、右、上、下格子移动,并且不能重复经过一个格子),则小明就能得到一个“666”奖励。
请你帮小明统计下他总共能得到多少“666”奖励。
输入格式:
输入第一行给出两个正整数m,n(1=<m,n<=100),随后是m行,每行包含n个0-9之间的数字。
输出格式:
先输出m行,每行包括n个整数,代表从当前格子出发得到的“666”奖励个数,中间用空格分割,最后一个数字后面不带空格。然后再在下一行输出得到的“666”奖励总数。
输入样例:
3 3
6 6 7
3 8 3
7 9 5
输出样例:
2 1 2
0 3 0
1 1 0
10
#include <iostream>
using namespace std;
int n,m;
int a[1000][1000],b[1000][1000];
int backtrack(int x1,int x2,int x3,int x4)
{
int x=0,y=0;
if(a[x1][x2+1]>=6&&x4!=3)
{
if(x3==2)
y++;
else
x+=backtrack(x1,x2+1,x3+1,1);
}
if(a[x1+1][x2]>=6&&x4!=4)
{
if(x3==2)
y++;
else
x+=backtrack(x1+1,x2,x3+1,2);
}
if(a[x1][x2-1]>=6&&x4!=1)
{
if(x3==2)
y++;
else
x+=backtrack(x1,x2-1,x3+1,3);
}
if(a[x1-1][x2]>=6&&x4!=2)
{
if(x3==2)
y++;
else
x+=backtrack(x1-1,x2,x3+1,4);
}
if(x3==2)
return y;
else
return x;
}
int main()
{
int i,j;
int sum=0;
cin>>m>>n;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
cin>>a[i][j];
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
{
if(a[i][j]>=6)
b[i][j]=backtrack(i,j,1,0);
else
b[i][j]=0;
}
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
if(j!=1)
cout<<" ";
cout<<b[i][j];
sum+=b[i][j];
}
cout<<endl;
}
cout<<sum<<endl;
return 0;
}
6 工作分配问题
设有n件工作分配给n个人。将工作i分配给第j个人所需的费用为cij 。 设计一个算法,对于给定的工作费用,为每一个人都分配1 件不同的工作,并使总费用达到最小。
输入格式:
输入数据的第一行有1 个正整数n (1≤n≤20)。接下来的n行,每行n个数,表示工作费用。
输出格式:
将计算出的最小总费用输出到屏幕。
输入样例:
在这里给出一组输入。例如:
3
10 2 3
2 3 4
3 4 5
输出样例:
在这里给出相应的输出。例如:
9
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int a[100][100],sum,minn,i,j,n;
bool b[100];
void dfs(int dep)
{
int r;
for (r=1;r<=n;++r)//dep表示第几个人,r表示工作。。。其实倒过来理解也未尝不可。。
if (!b[r])
{
b[r]=1;
sum+=a[dep][r];//a[dep][r]表示第dep个人做第r个工作的费用
if (dep==n)
{
if (sum<minn)
minn=sum;
}
else
if (sum<minn)//最优化剪枝。。如果当前的费用已经大于或等于当前已知的最小费用,那就没有搜索下去的必要了
dfs(dep+1);
sum-=a[dep][r];//回溯一步
b[r]=0;
}
}
int main()
{
scanf("%d",&n);
for (i=1;i<=n;++i)
for (j=1;j<=n;++j)
scanf("%d",&a[i][j]);
sum=0;
minn=2147483647;//赋成最大值,,我愿意写这么一长串你管我。。。
dfs(1);
printf("%d",minn);
return 0;
}