qdu 15信安 vjudge

目录



实验1 递归与分治

B - 又见GCD

有三个正整数a,b,c(0小于a,b,c<10^6),其中c不等于b。若a和c的最大公约数为b,现已知a和b,求满足条件的最小的c。

Input

第一行输入一个n,表示有n组测试数据,接下来的n行,每行输入两个正整数a,b。

Output

输出对应的c,每组测试数据占一行。

Sample Input

2
6 2
12 4

Sample Output

4
8
代码:

#include <iostream>

using namespace std;

int gcd(int a,int b);

int main()
{
    int n,i,j,a,b;
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>a>>b;
        for(j=2;j<a;j++)
        {
            if(gcd(a,j*b)==b)
            {
                cout<<j*b<<endl;
                break;
            }
        }

    }
    return 0;
}


int gcd(int a,int b)
{
    return (b>0)?gcd(b,a%b):a;
}

C - Rightmost Digit

Given a positive integer N, you should output the most right digit of N^N.

Input

The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case contains a single positive integer N(1<=N<=1,000,000,000).

Output

For each test case, you should output the rightmost digit of N^N.

Sample Input

2
3
4

Sample Output

7
6

Hint

In the first case, 3 * 3 * 3 = 27, so the rightmost digit is 7.
In the second case, 4 * 4 * 4 * 4 = 256, so the rightmost digit is 6.

代码:

#include <stdio.h>
#include <stdlib.h>

int main()
{
  int a[20] = {0,1,4,7,6,5,6,3,6,9,0,1,6,3,6,5,6,7,4,9};
    int i,t,n;
  scanf("%d",&t);
  for(i=0;i<t;i++)
  {
      scanf("%d",&n);
      n=n%20;
      printf("%d\n",a[n]);
  }

    return 0;
}

D - Can you find it?

Give you three sequences of numbers A, B, C, then we give you a number X. Now you need to calculate if you can find the three numbers Ai, Bj, Ck, which satisfy the formula Ai+Bj+Ck = X.

Input

There are many cases. Every data case is described as followed: In the first line there are three integers L, N, M, in the second line there are L integers represent the sequence A, in the third line there are N integers represent the sequences B, in the forth line there are M integers represent the sequence C. In the fifth line there is an integer S represents there are S integers X to be calculated. 1<=L, N, M<=500, 1<=S<=1000. all the integers are 32-integers.

Output

For each case, firstly you have to print the case number as the form “Case d:”, then for the S queries, you calculate if the formula can be satisfied or not. If satisfied, you print “YES”, otherwise print “NO”.

Sample Input

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

Sample Output

Case 1:
NO
YES
NO
代码:

#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
ll a[505],b[505],c[505],d[250010];

const int Mod = 500007;
int inf = 100000000;
ll mp[Mod];
void insert(ll u)
{
    ll v = u;
    if(v<0) v*=-1;
     int id = v%Mod;
     while(mp[id]!=inf) {id++;id%=Mod;}
     mp[id] = u;
}
 bool find(ll u){
     ll v = u;
     if(v<0) v*=-1;
     int id = v%Mod;
     while(mp[id] != inf){
         if(mp[id]==u) return true;
         id++;
         id%=Mod;
     }
     return false;
 }
 int main()
 {
     inf = inf*inf;//这里超int也没有关系,因为开始定义的int不够大
     int n1 , n2 , n3 ,cas = 1;
     while(~scanf("%d%d%d",&n1,&n2,&n3))
     {
         for(int i =0 ; i < n1; i++) scanf("%lld",&a[i]);
         for(int i =0 ;i < n2 ; i++) scanf("%lld",&b[i]);
         for(int i =0 ;i < n3; i++) scanf("%lld",&c[i]);
         int cc = 0;
         for(int i =0 ;i < n1; i++)
             for(int j = 0 ; j < n2 ; j++)
                 d[cc++] = a[i]+b[j];
         sort(d,d+cc);
         int n = unique(d,d+cc)-d;
        for(int i = 0 ; i < Mod ;i++) mp[i] = inf;
         for(int i =0 ;i < n; i++) insert(d[i]);
         ll s;
         scanf("%lld",&s);
         printf("Case %d:\n",cas++);
         for(int i = 0 ;i < s ;i++){
             ll x;
             scanf("%lld",&x);
             bool flag = false;
             for(int j= 0 ; flag == false&&j<n3;j++)
                 if(find(x-c[j]))flag = true;
             if(flag) puts("YES");
             else puts("NO");
         }
     }
     return 0;
 }

E - 汉诺塔II

经典的汉诺塔问题经常作为一个递归的经典例题存在。可能有人并不知道汉诺塔问题的典故。汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往上按大小顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一回只能移动一个圆盘。有预言说,这件事完成时宇宙会在一瞬间闪电式毁灭。也有人相信婆罗门至今仍在一刻不停地搬动着圆盘。恩,当然这个传说并不可信,如今汉诺塔更多的是作为一个玩具存在。Gardon就收到了一个汉诺塔玩具作为生日礼物。
  Gardon是个怕麻烦的人(恩,就是爱偷懒的人),很显然将64个圆盘逐一搬动直到所有的盘子都到达第三个柱子上很困难,所以Gardon决定作个小弊,他又找来了一根一模一样的柱子,通过这个柱子来更快的把所有的盘子移到第三个柱子上。下面的问题就是:当Gardon在一次游戏中使用了N个盘子时,他需要多少次移动才能把他们都移到第三个柱子上?很显然,在没有第四个柱子时,问题的解是2^N-1,但现在有了这个柱子的帮助,又该是多少呢?
  
Input
包含多组数据,每个数据一行,是盘子的数目N(1<=N<=64)。

Output
对于每组数据,输出一个数,到达目标需要的最少的移动数。

Sample Input

1
3
12

Sample Output

1
5
81    

代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main()
{
    int i,k,n;
    double s[65],t,min;
    s[1] = 1;
    s[2] = 3;
    for(i=3;i<65;i++)
    {
        min = 2*s[1] + pow(2,i-1)-1;
        for(k=2;k<i;k++)
    {
        t = 2*s[k] + pow(2,i-k)-1;
        if(t<min)
            min = t;
    }
        s[i] = min;
    }


    while(~scanf("%d",&n))
        printf("%.0f\n",s[n]);
    return 0;
}

实验2 动态规划(DP)

A - The Triangle

7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
(Figure 1)
Figure 1 shows a number triangle. Write a program that calculates the highest sum of numbers passed on a route that starts at the top and ends somewhere on the base. Each step can go either diagonally down to the left or diagonally down to the right.

Input

Your program is to read from standard input. The first line contains one integer N: the number of rows in the triangle. The following N lines describe the data of the triangle. The number of rows in the triangle is > 1 but <= 100. The numbers in the triangle, all integers, are between 0 and 99.

Output

Your program is to write to standard output. The highest sum is written as an integer.
Sample Input

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

Sample Output

30

代码:

#include<stdio.h>

int main() {
    int n, i, j;
    scanf("%d", &n);
    int **a = new int*[n];
    for (i = 0; i < n; ++i) {
        a[i] = new int[i + 1];
        for (j = 0; j <= i; ++j) {
            scanf("%d", &a[i][j]);
        }
    }
    for (i = n - 2; i >= 0; --i) {
        for (j = 0; j <= i; ++j) {
            a[i][j] += a[i + 1][j] > a[i + 1][j + 1] ? a[i + 1][j] : a[i + 1][j + 1];
        }
    }
    printf("%d", a[0][0]);
    return 0;
}

B - Multiplication Puzzle

The multiplication puzzle is played with a row of cards, each containing a single positive integer. During the move player takes one card out of the row and scores the number of points equal to the product of the number on the card taken and the numbers on the cards on the left and on the right of it. It is not allowed to take out the first and the last card in the row. After the final move, only two cards are left in the row.
The goal is to take cards in such order as to minimize the total number of scored points.
For example, if cards in the row contain numbers 10 1 50 20 5, player might take a card with 1, then 20 and 50, scoring
10*1*50 + 50*20*5 + 10*50*5 = 500+5000+2500 = 8000
If he would take the cards in the opposite order, i.e. 50, then 20, then 1, the score would be
1*50*20 + 1*20*5 + 10*1*5 = 1000+100+50 = 1150.

Input

The first line of the input contains the number of cards N (3 <= N <= 100). The second line contains N integers in the range from 1 to 100, separated by spaces.

Output

Output must contain a single integer - the minimal score.
Sample Input

6
10 1 50 50 20 5

Sample Output

3650

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;



int main()
{
    int n,a[101],work[101][101],i,j,k,l;
    while(~scanf("%d",&n))
    {
        for(i = 1; i<=n; i++)
            scanf("%d",&a[i]);
        memset(work,0,sizeof(work));
        for(l = 2; l<n; l++)
        {
            for(i = 2; i+l<=n+1; i++)
            {
                j = i+l-1;
                work[i][j] = 100000000;
                for(k = i; k<j; k++)
                    work[i][j] = min(work[i][j],work[i][k]+work[k+1][j]+a[i-1]*a[k]*a[j]);
            }
        }
        printf("%d\n",work[2][n]);
    }

    return 0;
}

C - Common Subsequence

A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, …, xm > another sequence Z = < z1, z2, …, zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, …, ik > of indices of X such that for all j = 1,2,…,k, x ij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.

Input

The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. 

Output

For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line. 

Sample Input

abcfbc         abfcab
programming    contest 
abcd           mnp

Sample Output

4
2
0

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char str1[500],str2[500];
    int i,j,m,n,c[500][500];
    while(~scanf("%s%s",str1,str2))
    {
        m = strlen(str1);
        n = strlen(str2);
        c[0][0] = 0;
        for(i=1; i<=m; i++)
            c[i][0] = 0;
        for(i=1; i<=n; i++)
            c[0][i] = 0;
        for(i=1; i<=m; i++)
            for(j=1; j<=n; j++)
            {
                if(str1[i-1] == str2[j-1])
                    c[i][j] = c[i-1][j-1]+1;
                else if(c[i-1][j] >= c[i][j-1])
                    c[i][j] = c[i-1][j];
                else
                    c[i][j] = c[i][j-1];
            }
        printf("%d\n",c[m][n]);
    }
    return 0;
}

D - Bone Collector

Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?

Input

The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.

Output

One integer per line representing the maximum of the total value (this number will be less than 2 31).

Sample Input

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

Sample Output

14

代码:

#include <stdio.h>
#include <stdlib.h>

int dp[1000][1000];
int main()
{
    int i,j,T,N,V,w[1000],value[1000];
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&V);
        for(i=1; i<=N; i++)
            scanf("%d",&value[i]);
        for(i=1; i<=N; i++)
            scanf("%d",&w[i]);
        for(i=0; i<N; i++)
        {
            dp[i][0] = 0;
            dp[0][i] = 0;
        }
        for(i=1; i<=N; i++)
            for(j=V; j>=0; j--)
            {
                if(j >= w[i])
                {
                    if(dp[i-1][j-w[i]]+value[i] >= dp[i-1][j])

                        dp[i][j] = dp[i-1][j-w[i]]+value[i];
                    else
                        dp[i][j] =dp[i-1][j];

                }
                else
                    dp[i][j] = dp[i-1][j];
            }
                printf("%d\n",dp[N][V]);



    }

    return 0;
}

E - 寒冰王座

 不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票(记住,只有一张钞票),为了防止自己在战斗中频繁的死掉,他决定给自己买一些道具,于是他来到了地精商店前.

死亡骑士:"我要买道具!"

地精商人:"我们这里有三种道具,血瓶150块一个,魔法药200块一个,无敌药水350块一个."

死亡骑士:"好的,给我一个血瓶."

说完他掏出那张N元的大钞递给地精商人.

地精商人:"我忘了提醒你了,我们这里没有找客人钱的习惯的,多的钱我们都当小费收了的,嘿嘿."

死亡骑士:"......"

死亡骑士想,与其把钱当小费送个他还不如自己多买一点道具,反正以后都要买的,早点买了放在家里也好,但是要尽量少让他赚小费.

现在死亡骑士希望你能帮他计算一下,最少他要给地精商人多少小费. 

Input

输入数据的第一行是一个整数T(1<=T<=100),代表测试数据的数量.然后是T行测试数据,每个测试数据只包含一个正整数N(1<=N<=10000),N代表死亡骑士手中钞票的面值.

注意:地精商店只有题中描述的三种道具.

Output

对于每组测试数据,请你输出死亡骑士最少要浪费多少钱给地精商人作为小费.

Sample Input

2
900
250

Sample Output

0
50

代码:

#define A 150
#define B 200
#define C 350
#define INF 0x3f3f3f3f
int main(){
    int i,j,k,T;
    int money;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&money);
        int min=INF;
         for(i=0;i<=money/A;i++)
            for(j=0;j<=money/B;j++)
                for(k=0;k<=money/C;k++){
                    int temp=money-i*A-j*B-k*C;
                    if(min>temp&&temp>=0)
                        min=temp;
                 }
        printf("%d\n",min);
    }
    return 0;
}

实验3 贪心算法

A - Scarecrow

Taso owns a very long field. He plans to grow different types of crops in the upcoming growing season. The area, however, is full of crows and Taso fears that they might feed on most of the crops. For this reason, he has decided to place some scarecrows at different locations of the field.
The field can be modeled as a 1 x N grid. Some parts of the field are infertile and that means you cannot grow any crops on them. A scarecrow, when placed on a spot, covers the cell to its immediate left and right along with the cell it is on.
Given the description of the field, what is the minimum number of scarecrows that needs to be placed so that all the useful section of the field is covered? Useful section refers to cells where crops can be grown.

Input

Input starts with an integer T (≤ 50), denoting the number of test cases.
Each case starts with a line containing an integer N (0 < N < 100). The next line contains N characters that describe the field. A dot (.) indicates a crop-growing spot and a hash (#) indicates an infertile region.

Output

For each case, print the case number and the number of scarecrows that need to be placed.

Sample Input

3

3

.#.

11

...##....##

2

##

Sample Output

Case 1: 1

Case 2: 3

Case 3: 0

代码:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int t,n,i,j,count;
    char a[200];
    scanf("%d",&t);
    for(i=1;i<=t;i++)
    {
        count = 0;
        scanf("%d",&n);
        scanf("%s",a);
        for(j = 0; j < n; j++)
        {
            if(a[j] == '#')
                continue;
            if(a[j] == '.')
            {
                count++;
            }
            j += 2;
        }
        printf("Case %d: %d\n",i,count);

    }
    return 0;
}

B - 迷瘴

通过悬崖的yifenfei,又面临着幽谷的考验——
幽谷周围瘴气弥漫,静的可怕,隐约可见地上堆满了骷髅。由于此处长年不见天日,导致空气中布满了毒素,一旦吸入体内,便会全身溃烂而死。
幸好yifenfei早有防备,提前备好了解药材料(各种浓度的万能药水)。现在只需按照配置成不同比例的浓度。
现已知yifenfei随身携带有n种浓度的万能药水,体积V都相同,浓度则分别为Pi%。并且知道,针对当时幽谷的瘴气情况,只需选择部分或者全部的万能药水,然后配置出浓度不大于 W%的药水即可解毒。
现在的问题是:如何配置此药,能得到最大体积的当前可用的解药呢?
特别说明:由于幽谷内设备的限制,只允许把一种已有的药全部混入另一种之中(即:不能出现对一种药只取它的一部分这样的操作)。

Input

输入数据的第一行是一个整数C,表示测试数据的组数;
每组测试数据包含2行,首先一行给出三个正整数n,V,W(1<=n,V,W<=100);
接着一行是n个整数,表示n种药水的浓度Pi%(1<=Pi<=100)。

Output

对于每组测试数据,请输出一个整数和一个浮点数;
其中整数表示解药的最大体积,浮点数表示解药的浓度(四舍五入保留2位小数);
如果不能配出满足要求的的解药,则请输出0 0.00。

Sample Input

3
1 100 10
100
2 100 24
20 30
3 100 24
20 20 30

Sample Output

0 0.00
100 0.20
300 0.23

代码:

#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
int main()
{
    int i,C,n,v,V,p[1000],W,s;
    double c;
    scanf("%d",&C);
    while(C--)
    {
        scanf("%d%d%d",&n,&V,&W);
        for(i=1; i<=n; i++)
            scanf("%d",&p[i]);
        sort(p+1,p+n+1);
        s = 0;
        i = 0;
        v = 0;
        c = 0;
        if(p[1] < W)
        {
            for(i=1; i<=n; i++)
            {
                if(s+p[i] > i*W)
                {
                    i--;
                    break;
                }
                s+=p[i];
                 c = (s*1.0)/(i*100);
            v = i*V;
            }

        }
        if(i == n+1)
            i--;
        printf("%d %.2f\n",i*V,c);
    }
    return 0;
}

C - 最短路

在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?

Input

>输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。

Output

对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

Sample Input

2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0

Sample Output

3
2
#include <cstdio>
#define INF 99999999

using namespace std;

int main()
{
    int i,j,t,N,M,m,n,c[101][101],dis[101],book[101];
    scanf("%d%d",&N,&M);
    while(M||N)
    {
        for(i=1; i<=N; i++)
        {
            for(j=1; j<=N; j++)
                c[i][j] = INF;
            book[i] = 0;
        }
        for(i=1; i<=N; i++)
            c[i][i] = 0;
        for(i=0; i<M; i++)
        {
            scanf("%d%d",&m,&n);
            scanf("%d",&t);
            c[m][n] = t;
            c[n][m] = t;
        }
        for(i=1; i<=N; i++)
            dis[i] = c[1][i];
        book[1] = 1;
        while(!book[N])
        {
            t = INF;
            for(i=2; i<=N; i++)
            {

                if(!book[i]&&dis[i]<t)
                {
                    t = dis[i];
                    j = i;
                }
            }
            book[j] = 1;
            for(i=1; i<=N; i++)
            {
                if(dis[j]+c[j][i]<dis[i])
                    dis[i] = dis[j]+c[j][i];
            }

        }
        printf("%d\n",dis[N]);
        scanf("%d%d",&N,&M);
    }
    return 0;
}

D - Agri-Net

Farmer John has been elected mayor of his town! One of his campaign promises was to bring internet connectivity to all farms in the area. He needs your help, of course.
Farmer John ordered a high speed connection for his farm and is going to share his connectivity with the other farmers. To minimize cost, he wants to lay the minimum amount of optical fiber to connect his farm to all the other farms.
Given a list of how much fiber it takes to connect each pair of farms, you must find the minimum amount of fiber needed to connect them all together. Each farm must connect to some other farm such that a packet can flow from any one farm to any other farm.
The distance between any two farms will not exceed 100,000.
Input
The input includes several cases. For each case, the first line contains the number of farms, N (3 <= N <= 100). The following lines contain the N x N conectivity matrix, where each element shows the distance from on farm to another. Logically, they are N lines of N space-separated integers. Physically, they are limited in length to 80 characters, so some lines continue onto others. Of course, the diagonal will be 0, since the distance from farm i to itself is not interesting for this problem.

Output

For each case, output a single integer length that is the sum of the minimum length of fiber required to connect the entire set of farms.

Sample Input

4
0 4 9 21
4 0 8 17
9 8 0 16
21 17 16 0

Sample Output

28
代码:

#include <cstdio>
#define INF 99999999

using namespace std;

int main()
{
    int i,j,t,N,count,sum,c[101][101],dis[101],book[101];

    while(~scanf("%d",&N))
    {
        count = 0;
        sum = 0;
        for(i=1; i<=N; i++)
        {
            for(j=1; j<=N; j++)
                scanf("%d",&c[i][j]);
            book[i] = 0;
        }
        for(i=1; i<=N; i++)
            dis[i] = c[1][i];
        book[1] = 1;
        count++;
        while(count<N)
        {
            t = INF;
            for(i=2; i<=N; i++)
            {

                if(!book[i]&&dis[i]<t)
                {
                    t = dis[i];
                    j = i;
                }
            }
            book[j] = 1;
            count++;
            sum+=dis[j];
            for(i=1; i<=N; i++)
            {
                if(!book[i] && dis[i]>c[j][i])
                    dis[i] = c[j][i];
            }

        }
        printf("%d\n",sum);
    }
    return 0;
}

实验4 回溯(dfs)

A 签到题

Recently, paleoanthropologists have found historical remains on an island in the Atlantic Ocean. The most inspiring thing is that they excavated in a magnificent cave and found that it was a huge tomb. Inside the construction,researchers identified a large number of skeletons, and funeral objects including stone axe, livestock bones and murals. Now, all items have been sorted, and they can be divided into N types. After they were checked attentively, you are told that there are Ai items of the i-th type. Further more, each item of the i-th type requires Bi
million dollars for transportation, analysis, and preservation averagely. As your job, you need to calculate the total expenditure.

Input

The first line of input contains an integer T which is the number of test cases. For each test case, the first line contains an integer N which is the number of types. In the next N lines, the i-th line contains two numbers Ai and Bi
as described above. All numbers are positive integers and less than 101.

Output

For each case, output one integer, the total expenditure in million dollars.

Sample Input

1
2
1 2
3 4

Sample Output

14

有N种物品,告诉这N 种商品的数量Ai和单价Bi,求总价。sum=A1xB1+A2xB2+…+AnxBn。

代码:

#include <iostream>

using namespace std;

int main()
{
    int t,n,a,b,sum;
    cin>>t;
    while(t--)
    {
        cin>>n;
        sum = 0;
        while(n--)
        {
            cin>>a>>b;
            sum += a*b;
        }
        cout<<sum<<endl;
    }
    return 0;
}

B N皇后问题

在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。你的任务是,对于给定的N,求出有多少种合法的放置方法。

Input

共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
Output

共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。

Sample Input

1
8
5
0

Sample Output

1
92
10

代码:
N叉树方法超时

#include <cmath>
#include <memory.h>
using namespace std;

int n,count,x[11],book[11];

bool check(int m,int n)
{
    int i;
    if(book[n])
        return false;
    for(i=1;i<m;i++)
        if(abs(m-i)==abs(n-x[i]))
        return false;
    return true;
}

void dfs(int d)
{
    int i;
    if(d == n+1)
    {
        count++;
        return;
    }
    for(i=1;i<=n;i++)
    {
        if(check(d,i))
        {
           book[i] = 1;
           x[d] = i;
           dfs(d+1);
           book[i] = 0;
        }
    }
}
int main()
{
    cin>>n;
    while(n)
    {
        count = 0;
        memset(book,0,sizeof(book));
        dfs(1);
        cout<<count<<endl;
        cin>>n;
    }
    return 0;
}

最后打表通过(打表是预先把所有的输入对应的输出求解保存下来,给定一个输入直接输出预计算的答案。


using namespace std;

int main()
{
    int n,a[11] = {0,1,0,0,2,10,4,40,92,352,724};
    cin>>n;
    while(n)
    {
          cout <<a[n]<< endl;
          cin>>n;
    }

    return 0;
}

C 最大团问题(子集树)

Given a graph G(V, E), a clique is a sub-graph g(v, e), so that for all vertex pairs v1, v2 in v, there exists an edge (v1, v2) in e. Maximum clique is the clique that has maximum number of vertex.
Input
Input contains multiple tests. For each test:
The first line has one integer n, the number of vertex. (1 < n <= 50)
The following n lines has n 0 or 1 each, indicating whether an edge exists between i (line number) and j (column number).
A test with n = 0 signals the end of input. This test should not be processed.

Output

One number for each test, the number of vertex in maximum clique.

Sample Input

5
0 1 1 0 1
1 0 1 1 1
1 1 0 1 1
0 1 1 0 1
1 1 1 1 0
0

Sample Output

4

题目大意在给定的一个图中,找到一个最大团,即找到节点最多的一个完全图(完全图是指,图中每一个节点到其他节点都有边相连),输出最大团的节点数。用子集树解决。左剪枝(约束):for循环判断第i个节点之前的点是否选中了,若选中了该点则判断和i是否有边相连;右剪枝(限界):每得到一个解时更新bestn,判断当前选择的节点数加上所有判断的节点数是否大于bestn,cn+n-i>bestn。

代码:

#include <stdlib.h>
int a[51][51],n,x[51],bestn,cn;
void backtrack(int i)
{
    if(i>n)
    {
        bestn=cn;
        return;
    }
    int ok=1;
    for(int j=1; j<i; j++)//判断是否和已经选中的点都有边相连
    {
        if(x[j]&&a[i][j]==0)/*x[j]记录第j个点是否被选中,a[i][j]记录ij之间是否有边*/
        {
            ok=0;
            break;
        }
    }
    if(ok)
    {
        x[i] = 1;
        cn++;
        backtrack(i+1);
        x[i] = 0;
        cn--;
    }
    if(cn+n-i>bestn)
    {
        x[i]=0;
        backtrack(i+1);
    }
}

int main()
{
    int i,j;
    while(scanf("%d",&n),n)
    {
        bestn = 0;
        cn = 0;
        for(i=1; i<=n; i++)
            for(j=1; j<=n; j++)
                scanf("%d",&a[i][j]);
        backtrack(1);
        printf("%d\n",bestn);
    }
    return 0;
}

D - 图的M着色(m叉树)

In mathematics, the four color theorem, or the four color map theorem, states that, given any separation of a plane into contiguous regions, producing a figure called a map, no more than four colors are required to color the regions of the map so that no two adjacent regions have the same color.
— Wikipedia, the free encyclopedia
In this problem, you have to solve the 4-color problem. Hey, I’m just joking.
You are asked to solve a similar problem:
Color an N × M chessboard with K colors numbered from 1 to K such that no two adjacent cells have the same color (two cells are adjacent if they share an edge). The i-th color should be used in exactly c i cells.
Matt hopes you can tell him a possible coloring.

Input

The first line contains only one integer T (1 ≤ T ≤ 5000), which indicates the number of test cases.
For each test case, the first line contains three integers: N, M, K (0 < N, M ≤ 5, 0 < K ≤ N × M ).
The second line contains K integers c i (c i > 0), denoting the number of cells where the i-th color should be used.
It’s guaranteed that c 1 + c 2 + · · · + c K = N × M .

Output

For each test case, the first line contains “Case #x:”, where x is the case number (starting from 1).
In the second line, output “NO” if there is no coloring satisfying the requirements. Otherwise, output “YES” in one line. Each of the following N lines contains M numbers seperated by single whitespace, denoting the color of the cells.If there are multiple solutions, output any of them.

Sample Input

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

Sample Output

Case #1:
NO
Case #2:
YES
4 3 4
2 1 2
4 3 4
Case #3:
YES
1 2 3
2 3 1
Case #4:
YES
1 2
2 3
3 1
给NxM的棋盘涂色,读入K种颜色以及每种颜色的使用次数,要求相邻的方格颜色不同,找到解输出YES并输出涂色方案,找不到输出NO

#include <stdio.h>
#include <stdlib.h>
int k,flag,m,n,a[2500],map[52][52];
void backtrack(int i,int j)
{
    int c;
    j++;
    if(j>m)
    {
        i++;
        j=1;
    }
    if(i>n)
    {
        flag = 1;
        return;
    }
    for(c=1; c<=k; c++)
    {
        if(a[c]>0&&map[i][j-1]!=c&&map[i-1][j]!=c)
        {
            a[c]--;
            map[i][j] = c;
            backtrack(i,j);
            if(flag==1)
                return;
            a[c]++;
        }
    }
}

int main()
{
    int c,i,j,t;
    scanf("%d",&t);
    for(c=1; c<=t; c++)
    {
        flag = 0;
        scanf("%d%d%d",&n,&m,&k);
        for(i=1; i<=k; i++)
            scanf("%d",&a[i]);
        for(i=0; i<=m+1; i++)
        {
            map[0][i] = 0;
            map[n+1][i] = 0;
        }
        for(i=0; i<=n+1; i++)
        {
            map[i][0] = 0;
            map[i][m+1] = 0;
        }
        backtrack(1,0);
        printf("Case #%d:\n",c);
        if(flag==0)
            printf("NO\n");
        else
        {
            printf("YES\n");
            for(i=1; i<=n; i++)
            {
                for(j=1; j<=m; j++)
                    printf("%d ",map[i][j]);
                printf("\n");
            }
        }
    }

    return 0;
}

E - 数独问题

自从2006年3月10日至11日的首届数独世界锦标赛以后,数独这项游戏越来越受到人们的喜爱和重视。
据说,在2008北京奥运会上,会将数独列为一个单独的项目进行比赛,冠军将有可能获得的一份巨大的奖品———HDU免费七日游外加lcy亲笔签名以及同hdu acm team合影留念的机会。
所以全球人民前仆后继,为了奖品日夜训练茶饭不思。当然也包括初学者linle,不过他太笨了又没有多少耐性,只能做做最最基本的数独题,不过他还是想得到那些奖品,你能帮帮他吗?你只要把答案告诉他就可以,不用教他是怎么做的。
数独游戏的规则是这样的:在一个9x9的方格中,你需要把数字1-9填写到空格当中,并且使方格的每一行和每一列中都包含1-9这九个数字。同时还要保证,空格中用粗线划分成9个3x3的方格也同时包含1-9这九个数字。比如有这样一个题,大家可以仔细观察一下,在这里面每行、每列,以及每个3x3的方格都包含1-9这九个数字。
例题:
这里写图片描述
答案:
这里写图片描述

Input

本题包含多组测试,每组之间由一个空行隔开。每组测试会给你一个 9*9 的矩阵,同一行相邻的两个元素用一个空格分开。其中1-9代表该位置的已经填好的数,问号(?)表示需要你填的数。

Output

对于每组测试,请输出它的解,同一行相邻的两个数用一个空格分开。两组解之间要一个空行。
对于每组测试数据保证它有且只有一个解。

Sample Input

7 1 2 ? 6 ? 3 5 8
? 6 5 2 ? 7 1 ? 4
? ? 8 5 1 3 6 7 2
9 2 4 ? 5 6 ? 3 7
5 ? 6 ? ? ? 2 4 1
1 ? 3 7 2 ? 9 ? 5
? ? 1 9 7 5 4 8 6
6 ? 7 8 3 ? 5 1 9
8 5 9 ? 4 ? ? 2 3

Sample Output

7 1 2 4 6 9 3 5 8
3 6 5 2 8 7 1 9 4
4 9 8 5 1 3 6 7 2
9 2 4 1 5 6 8 3 7
5 7 6 3 9 8 2 4 1
1 8 3 7 2 4 9 6 5
2 3 1 9 7 5 4 8 6
6 4 7 8 3 2 5 1 9
8 5 9 6 4 1 7 2 3

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#define MAX 10
using namespace std;

char c;
int flag,flag1,i,j,m[MAX][MAX],qm[MAX*MAX][2],sum;//qm记录问号点的坐标,sum记录问号的个数
bool row[MAX][MAX],column[MAX][MAX],small[MAX][MAX];//记录行列和小9方格出现过哪些数

void dfs(int i)
{
    if(i==sum)
    {
        for(int k=1; k<MAX; k++)
        {
            for(int j=1; j<MAX; j++)
            {
                cout<<m[k][j];
                if(j < MAX-1)
                    cout<<" ";
            }
            cout<<"\n";
        }
        flag =1;
        return;
    }
    for(int k=1; k<MAX; k++)
    {
        if(!row[qm[i][0]][k]&&!column[qm[i][1]][k]&&!small[((qm[i][0]-1)/3)*3+(qm[i][1]-1)/3+1][k])
        {
            row[qm[i][0]][k] = true;
            column[qm[i][1]][k] = true;
            small[((qm[i][0]-1)/3)*3+(qm[i][1]-1)/3+1][k] = true;
            m[qm[i][0]][qm[i][1]] = k;
            dfs(i+1);
            if(flag)
                return;
            row[qm[i][0]][k] = false;
            column[qm[i][1]][k] = false;
            small[((qm[i][0]-1)/3)*3+(qm[i][1]-1)/3+1][k] = false;
        }
    }
}

int main()
{
    flag1 = 0;
    while(1)
    {
        memset(row,false,sizeof(row));
        memset(column,false,sizeof(column));
        memset(small,false,sizeof(small));
        sum = 1;
        for(int i=1; i<MAX; i++)
        {
            for(int j=1; j<MAX; j++)
            {
                if(!(cin>>c))
                    return 0;
                if(c == '?')
                {
                    qm[sum][0]=i;
                    qm[sum][1]=j;
                    sum++;
                    continue;
                }
                else
                {
                    m[i][j] = c-'0';
                    row[i][m[i][j]] = true;
                    column[j][m[i][j]] = true;
                    small[((i-1)/3)*3+(j-1)/3+1][m[i][j]] = true;
                }
            }
        }
        flag = 0;
        if(flag1++)
            cout<<"\n";
        dfs(1);
    }
    return 0;
}

实验5 分支限界(bfs)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值