F - Free DIY Tour(动态规划,搜索也行)

这道题可用动态规划也可以用搜索,下面都写一下

Description

Weiwei is a software engineer of ShiningSoft. He has just excellently fulfilled a software project with his fellow workers. His boss is so satisfied with their job that he decide to provide them a free tour around the world. It's a good chance to relax themselves. To most of them, it's the first time to go abroad so they decide to make a collective tour. 

The tour company shows them a new kind of tour circuit - DIY circuit. Each circuit contains some cities which can be selected by tourists themselves. According to the company's statistic, each city has its own interesting point. For instance, Paris has its interesting point of 90, New York has its interesting point of 70, ect. Not any two cities in the world have straight flight so the tour company provide a map to tell its tourists whether they can got a straight flight between any two cities on the map. In order to fly back, the company has made it impossible to make a circle-flight on the half way, using the cities on the map. That is, they marked each city on the map with one number, a city with higher number has no straight flight to a city with lower number. 

Note: Weiwei always starts from Hangzhou(in this problem, we assume Hangzhou is always the first city and also the last city, so we mark Hangzhou both 1 and N+1), and its interesting point is always 0. 

Now as the leader of the team, Weiwei wants to make a tour as interesting as possible. If you were Weiwei, how did you DIY it? 
 

Input

The input will contain several cases. The first line is an integer T which suggests the number of cases. Then T cases follows. 
Each case will begin with an integer N(2 ≤ N ≤ 100) which is the number of cities on the map. 
Then N integers follows, representing the interesting point list of the cities. 
And then it is an integer M followed by M pairs of integers [Ai, Bi] (1 ≤ i ≤ M). Each pair of [Ai, Bi] indicates that a straight flight is available from City Ai to City Bi. 
 

Output

For each case, your task is to output the maximal summation of interesting points Weiwei and his fellow workers can get through optimal DIYing and the optimal circuit. The format is as the sample. You may assume that there is only one optimal circuit. 

Output a blank line between two cases. 
 

Sample Input

2 3 0 70 90 4 1 2 1 3 2 4 3 4 3 0 90 70 4 1 2 1 3 2 4 3 4
 

Sample Output

CASE 1# points : 90 circuit : 1->3->1 CASE 2# points : 90 circuit : 1->2->1
 
 
问题:输入测试案例数t
   输入城市数n
   依次输入1到n号城市中每个城市的有趣程度
   输入道路的数目m
   输入m组数据(a, b)表示a和b城市相连
   已知:出发的城市标号1和n+1,因为它不仅是起点,同时也是终点,它的有趣度为0(初始化的时候一定要记得,不然会很惨啊啊啊啊……)
      只能由标号小的城市出发到达标号大的城市
 
   wrong answer原因:初始化的时候忽略了intrest[n+1] = 0;
             输出路径的时候注意并非经过所有的城市,所以输出的城市数目不等于总城市数
   易错点:注意每个案例之间要有一行空行,最后一个案例后面没有空行
       
    分析:用Link[i][j]存储i城市和j城市是否相连,intrest[i]存储城市i的有趣度dp[i]存储到达i城市的时候的最大有趣度
      dp[i] = max(dp[j]+intrest[i], dp[i])
      到达i城市之前可能在除了i城市和起点之外的任意一个城市,遍历经过i城市之前的城市为任意城市,把到达i城市的时候的有趣度更新为其中最大的一个数代码中具体讲
 
#include <stdio.h>
#include <string.h>
bool link[105][105];
int intrest[105], dp[105], last[105], path[105];
int main()
{
    int t, case_num = 1;
    //freopen("input.txt", "r", stdin);
    scanf("%d", &t);
    while(t--)
    {
        int n, m, i, j;
        memset(link, 0, sizeof(link));
        memset(dp, 0, sizeof(dp));
        last[1] = 0; //last记录上一个走的城市的标号,last[1] = 0是为了让追溯到第一个城市之后就不继续追溯了
        scanf("%d", &n);
        if(case_num != 1)
            printf("\n");
        for(i = 1; i <= n; i++)
        {
            scanf("%d", &intrest[i]);
        }
        intrest[i] = 0; //注意i城市有趣度为0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        scanf("%d", &m);
        for(int i = 0; i < m; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            link[a][b] = link[b][a] = 1;
        }
        for(i = 2; i <= n+1; i++) //假设目标城市标号为i(注意到达它之前经过的城市的标号都小于它)
        {
            for(j = 1; j < i; j++)
                //遍历到达i城市之前所在的城市的标号的所有可能性,
                //更新到达i城的时候的有趣度之和为所有情况中最大的
            {
                if(dp[j]+intrest[i] > dp[i] && link[i][j])
                {
                    dp[i] = dp[j]+intrest[i];
                   last[i] = j;
                }
            }
        }
        j = 0;
        i = n+1;
        while(last[i])
        {
            path[j++] = last[i];
            i = last[i];
        }
        printf("CASE %d#\n", case_num++);
        printf("points : %d\n", dp[n+1]);
        printf("circuit : ");
        for(i = j-1; i >= 0; i--)//注意输出的个数并非为城市数目!!!!!!!!!!!!!
        {
            printf("%d->", path[i]);
        }
        printf("1\n");
    }
    return 0;
}

 下面是深搜的代码及讲解

/*
    问题:输入测试案例数t
          输入城市数目n
          接下来n个数字分别代表标号为1-n的城市的风景度
          接下来一个数字m,代表道路数目
          接下来m对数字(a, b)代表a城市和b城市是相连的
         要求只能从标号小的城市走到标号大的城市,最后回到城市1,所以城市1的标号也是n+1
         且城市1和城市n+1的风景度都为0
        问:按照上述条件从1出发,所能遍历的最大风景度是多少

    分析:由于出发城市固定为1,终点城市固定为n+1(也即1)
          除了起点之外,任意一步的出发城市可能有多种选择,下一步也有多种选择,
          因此可以使用深度搜索来做,遍历所有的可能,当遇到回到起点的时候风景度总和大于上一个风景度总和的时候
          更新风景度为其中的最大值,并把记录最大风景度所走的路线也更新一下
          深搜的参数为进入深搜之前的风景度、进入深搜的时候所在的城市,记录这是第几步的一个数
*/
#include <stdio.h>
#include <string.h>
#define M 105
int value[M], n, m, maxi, road_len;
bool link[M][M];
int path_tmp[M], ans[M];
void dfs(int step_num, int sum, int now_point)
{
    int i, j;
    for(i = now_point+1; i <= n; i++)
    {
    /*
            注意并非从1到n+1然后值最大的时候更新sum,因为即使所得的值最大,但是回不到起点也不行滴
            for循环遍历第step_num步可能走的城市号的所有可能性
            如果有路,那就走,并且看一下走这步路之后是否下一步就可以通往n+1城市了
            如果可以通往n+1城市,那么更新最大风景值,并记录这个路径
    */
        if(link[now_point][i])
        {
            path_tmp[step_num] = i;
            if(link[i][n+1])
            {
                path_tmp[step_num+1] = 1;
                if(sum +value[i]> maxi)
                {
                    maxi = sum + value[i];
                    road_len = step_num+1;
                    for(j = 1; j <= road_len; j++)
                    {
                        ans[j] = path_tmp[j];
                    }
                }
            }
            dfs(step_num+1, sum+value[i], i);
        }
    }
}
void init()
{
    ans[0] = 1;//第一步走城市1,即起点
    maxi = 0; //把最大风景值初始为0
    road_len = 1;//初始只经过了城市1,所以路长为1
    memset(link, 0, sizeof(link));//所有城市都没有路
    scanf("%d", &n);
    for(int i = 1; i <= n; i++)
        scanf("%d", &value[i]);
    value[1] = value[n+1] = 0;//城市1和城市n+1的风景度为0
    scanf("%d", &m);
    for(int i = 0; i < m; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        link[a][b] = link[b][a] = 1; //因为路是双向的,相对的
    }
}
int main()
{
    int t, case_num = 1;
    //freopen("input.txt", "r", stdin);
    scanf("%d", &t);
    while(t--)
    {
        init();
        if(case_num != 1)
            printf("\n"); // 每个案例之间输出一行空行,但是最后一个输出之后不用输出空行
        printf("CASE %d#\n", case_num++);
        dfs(1, 0, 1);//初始时候该走第一步了,这时候风景度为0,当前所在城市1
        printf("points : %d\n", maxi); //刚开始竟然把这句话放在dfs前面了,下次表粗心了,wrong了两次
        if(road_len != 1)
        {
            printf("circuit : ");
            for(int i = 0; i < road_len; i++)
                printf("%d->", ans[i]);
            printf("%d\n", ans[road_len]);
        }
    }
    return 0;
}

 

posted on 2015-10-19 22:12  张明明_1  阅读(388)  评论(0编辑  收藏  举报

导航