牛客小白月赛22 - 收集纸片(全排列、TSP问题、状压DP)

 牛客小白月赛22 - 收集纸片(全排列、TSP问题、状压DP)

链接:https://ac.nowcoder.com/acm/contest/4462/D
来源:牛客网


时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

 

题目描述

我们把房间按照笛卡尔坐标系进行建模之后,每个点就有了一个坐标。
假设现在房子里有些纸片需要被收集,收集完纸片你还要回归到原来的位置,你需要制定一个策略来使得自己行走的距离最短。
你只能沿着 x 轴或 y 轴方向移动,从位置 (i,j) 移动到相邻位置 (i+1,j),(i-1,j),(i,j+1) 或 (i,j-1) 距离增加 1。

输入描述:

在第一行中给出一个T,1T10, 代表测试数据的组数。
对于每组输入,在第一行中给出房间大小,第二行给出你的初始位置。
接下来给出一个正整数 n,1≤n≤10 代表纸片的个数。
接下来 n 行,每行一个坐标代表纸片的位置。
保证房间小于 20×20 ,纸片一定位于房间内。

输出描述:

对于每组输入,在一行中输出答案。
格式参见样例。

输入

1
10 10
1 1
4
2 3
5 5
9 4
6 5

输出

The shortest path has length 24

 

 

一、全排列暴力枚举

因为最多只有10片纸片,所以大可枚举所有的收集顺序,然后在其中取一个最小值。

我们可以用求1~k的全排列,计算所有可能的走法,由于纸片数不超过10,所以走法最多只有10!种。

直接全排列计算即可,用DFS或next_permutation均可。

 

DFS求全排列:

 1 #include <bits/stdc++.h>
 2 typedef long long LL;
 3 const int INF=0x3f3f3f3f;
 4 const double eps =1e-8;
 5 const int mod=1e9+7;
 6 const int maxn=1e5+10;
 7 using namespace std;
 8 
 9 int n,m,k;
10 int stx,sty;
11 pair<int,int> pos[15];
12 int vis[15];
13 int ans;
14 
15 void DFS(int x,int y,int num,int step)
16 {
17     if(num==0)
18     {
19         step+=abs(x-stx)+abs(y-sty);
20         if(step < ans) ans=step;
21         return ;
22     }
23     for(int i=1;i<=k;i++)
24     {
25         if(vis[i]==0)
26         {
27             vis[i]=1;
28             int xx=pos[i].first, yy=pos[i].second;
29             DFS(xx,yy,num-1,step+abs(xx-x)+abs(yy-y));
30             vis[i]=0;
31         }
32     }
33 }
34 
35 
36 int main()
37 {
38     #ifdef DEBUG
39     freopen("sample.txt","r",stdin);
40     #endif
41     
42     int T;
43     scanf("%d",&T);
44     while(T--)
45     {
46         memset(vis,0,sizeof(vis));
47         ans=INF;
48         scanf("%d %d %d %d %d",&n,&m,&stx,&sty,&k);
49         for(int i=1;i<=k;i++)
50         {
51             int x,y;
52             scanf("%d %d",&x,&y);
53             pos[i]={x,y};
54         }
55         DFS(stx,sty,k,0);
56         printf("The shortest path has length %d\n",ans);
57     }
58     
59     return 0;
60 }

 

 

next_permutation求全排列

 1 #include <bits/stdc++.h>
 2 typedef long long LL;
 3 const int INF=0x3f3f3f3f;
 4 const double eps =1e-8;
 5 const int mod=1e9+7;
 6 const int maxn=1e5+10;
 7 using namespace std;
 8 
 9 pair<int,int> pos[15];
10 int rk[15];
11 
12 int main()
13 {
14     #ifdef DEBUG
15     freopen("sample.txt","r",stdin);
16     #endif
17     
18     int T;
19     scanf("%d",&T);
20     while(T--)
21     {
22         int n,m,k,stx,sty;
23         int ans=INF;
24         scanf("%d %d %d %d %d",&n,&m,&stx,&sty,&k);
25         for(int i=1;i<=k;i++)
26         {
27             int x,y;
28             scanf("%d %d",&x,&y);
29             pos[i]={x,y}; rk[i]=i;
30         }
31         do
32         {
33             int sum=0, prex=stx, prey=sty;
34             for(int i=1;i<=k;i++)
35             {
36                 int x=pos[rk[i]].first, y=pos[rk[i]].second;
37                 sum+=abs(x-prex)+abs(y-prey);
38                 prex=x; prey=y;
39             }
40             ans=min(ans,sum+abs(prex-stx)+abs(prey-sty));
41         }while(next_permutation(rk+1,rk+1+k));
42         printf("The shortest path has length %d\n",ans);
43     }
44     
45     return 0;
46 }

 

 

 

 

二、状压dp

把每个纸片都不重不漏地恰好经过一次,很容易想到旅行商问题,即TSP问题(每个城市只能拜访一次,而且最后要回到原来出发的城市。),可以用状压dp。

借助二进制数来进行DP。

 

 1 #include <bits/stdc++.h>
 2 typedef long long LL;
 3 const int INF=0x3f3f3f3f;
 4 const double eps =1e-8;
 5 const int mod=1e8;
 6 const int maxn=1e5+10;
 7 using namespace std;
 8 
 9 pair<int,int> pos[15];
10 int dp[1<<11][11];//dp[i][j]目前走过的状态是二进制i,且最后一个走过的点是j 
11 
12 int cal(int a,int b)
13 {
14     return abs(pos[b].first-pos[a].first)+abs(pos[b].second-pos[a].second);
15 }
16 
17 int main()
18 {
19     #ifdef DEBUG
20     freopen("sample.txt","r",stdin);
21     #endif
22     
23     int T;
24     scanf("%d",&T);
25     while(T--)
26     {
27         int n,m,k;
28         scanf("%d %d %d %d %d",&n,&m,&pos[0].first,&pos[0].second,&k);//pos[0]是初始位置
29         for(int i=1;i<=k;i++)
30         {
31             int x,y;
32             scanf("%d %d",&x,&y);
33             pos[i]=make_pair(x,y);
34         }
35         int ans=INF;
36         memset(dp,INF,sizeof(dp));
37         for(int i=1;i<=k;i++)
38             dp[1<<(i-1)][i]=cal(0,i);
39         for(int s=0;s<(1<<k);s++)
40         {
41             for(int i=1;i<=k;i++) //遍历该状态的一个点i作为最后一个经过的点
42             {
43                 if(s & (1<<(i-1)))
44                 {
45                     for(int j=1;j<=k;j++)//遍历该状态的一个点j作为从j走到i
46                     {
47                         if(s & (1<<(j-1)))
48                             dp[s][i]=min(dp[s][i],dp[s^(1<<(i-1))][j]+cal(i,j));
49                     }
50                 }
51             }
52         }
53         for(int i=1;i<=k;i++)
54             ans=min(ans,dp[(1<<k)-1][i]+cal(i,0));
55         printf("The shortest path has length %d\n",ans);
56     }
57     
58     return 0;
59 }

 

 

 

 状压DP讲解:https://www.cnblogs.com/Tony-Double-Sky/p/9283254.html

 

TSP问题DP详解:https://blog.csdn.net/qq_39559641/article/details/101209534

关于TSP的一些题:https://blog.csdn.net/yjr3426619/article/details/83387962

 

 

 

 

 

 

-

posted @ 2020-03-26 11:16  jiamian22  阅读(312)  评论(0编辑  收藏  举报