Travelling

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 3905    Accepted Submission(s): 1234

Problem Description
After coding so many days,Mr Acmer wants to have a good rest.So travelling is the best choice!He has decided to visit n cities(he insists on seeing all the cities!And he does not mind which city being his start station because superman can bring him to any
city at first but only once.), and of course there are m roads here,following a fee as usual.But Mr Acmer gets bored so easily that he doesn't want to visit a city more than twice!And he is so mean that he wants to minimize the total fee!He is lazy you see.So
he turns to you for help.
 
Input
There are several test cases,the first line is two intergers n(1<=n<=10) and m,which means he needs to visit n cities and there are m roads he can choose,then m lines follow,each line will include three intergers a,b and c(1<=a,b<=n),means there is a road between
a and b and the cost is of course c.Input to the End Of File.
 
Output
Output the minimum fee that he should pay,or -1 if he can't find such a route.
 
Sample Input
2 1
1 2 100
3 2
1 2 40
2 3 50
3 3
1 2 3
1 3 4
2 3 10
 
Sample Output
100
90
7

DP+状态压缩:每一个点最多仅仅能经过2次,考虑用3进制存储状态;

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 12
#define M 59050
#define LL long long
const int inf=0x1f1f1f1f; //注意初始化值
int tri[N]= {0,1,3,9,27,81,243,729,2187,6561,19683,59049};
int g[N][N];
int dig[M][N]; //dig[i][j]记录I状态下J点是否出现,出现几次
int dp[M][N]; //dp[s][j] 在状态s下,以j为终点的最短距离
void inti() //求出每一个状态s相应的3进制位的信息
{
int i,j,t;
for(i=1;i<M;i++)
{
for(t=i,j=1;j<=10;j++)
{
dig[i][j]=t%3; //求出该状态下到达每一个的城市次数
t/=3;
if(!t) break;
}
}
}
int main()
{
int i,j,a,b,c;
int n,m,s;
inti();
while(scanf("%d%d",&n,&m)!=-1)
{
memset(g,inf,sizeof(g));
memset(dp,inf,sizeof(dp));
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
g[a][b]=g[b][a]=min(c,g[a][b]);
}
for(i=1;i<=n;i++) //起始状态。能够任一城市为起点。
dp[tri[i]][i]=0; //距离自然初始化为0
int ans=inf;
for(s=1;s<tri[n+1];s++) //在s状态以i为终点时更新其它状态的值
{
int f=1;
for(i=1;i<=n;i++)
{
if(dig[s][i]==0) //推断当前状态S下,每一个城市是否都已到达
f=0;
if(dp[s][i]==inf)
continue;
for(j=1;j<=n;j++) //dp[s][i]状态到dp[s+tri[j]][j]状态
{
if(g[i][j]==inf||i==j||dig[s][j]>=2)
continue;
int news=s+tri[j];
dp[news][j]=min(dp[news][j],dp[s][i]+g[i][j]);
}
}
if(f)
for(i=1;i<=n;i++)
ans=min(ans,dp[s][i]);
}
if(ans==inf)
ans=-1;
printf("%d\n",ans);
}
return 0;
}
</pre><p></p><p></p><p><span style="font-size:18px; color:#33ccff">bfs+状态压缩:</span></p><p><span style="color:rgb(51,204,255); font-size:18px">開始时把每个点都入队,模拟3进制处理每个状态,最后+优化。

</span></p><p></p><pre code_snippet_id="479354" snippet_file_name="blog_20141004_2_7195338" name="code" class="cpp">#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
#define N 12
#define LL long long
const int inf=0x3fffffff;
int g[N][N];
int n,m,ans;
int mark[N][60000];
struct node
{
int x,t,s,cnt; //位置、时间、状态、个数
friend bool operator<(node a,node b)
{
return a.t>b.t;
}
};
int gettmp(int x,int k) //得到X在3进制下的第K位是多少
{ //推断该点是否经过了。经过了几次
int t;
while(x)
{
t=x%3;
k--;
if(k==0)
break;
x/=3;
}
return k?0:t;
}
void inti() //初始化数组
{
int i,j;
for(i=1;i<=n;i++)
{
for(j=0;j<(int)pow(3,n);j++)
mark[i][j]=inf;
}
}
void bfs()
{
int i;
priority_queue<node>q;
node cur,next;
for(i=1;i<=n;i++)
{
cur.x=i;
cur.s=pow(3,(i-1));
cur.t=0;
cur.cnt=1;
q.push(cur);
mark[i][0]=0;
}
while(!q.empty())
{
cur=q.top();
q.pop();
for(i=1;i<=n;i++)
{
if(g[cur.x][i]==inf) //此路不通
continue;
next.cnt=cur.cnt;
next.s=cur.s;
next.t=cur.t+g[cur.x][i];
if(ans<next.t) //优化非常重要
continue;
next.x=i;
int t=gettmp(next.s,i); //该点经过了几次,
if(t>=2) //经过2次后就不能走了
continue;
next.s+=pow(3,(i-1)); //该点经过次数加一
if(t==0) //经过一个新景点
{
next.cnt++;
if(next.cnt==n)
{
ans=min(ans,next.t);
continue;
}
}
if(next.t<mark[i][next.s])
{
mark[i][next.s]=next.t;
q.push(next);
}
}
}
}
int main()
{
int a,b,c,i,j;
while(scanf("%d%d",&n,&m)!=-1)
{
for(i=0;i<=n;i++)
for(j=1;j<=n;j++)
g[i][j]=(i==j? 0:inf);
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
g[a][b]=g[b][a]=min(g[a][b],c);
}
ans=inf;
inti();
bfs();
if(ans==inf)
ans=-1;
printf("%d\n",ans);
}
return 0;
}

版权声明:本文博客原创文章,博客,未经同意,不得转载。

hdu 3001 Travelling (TSP问题 )的更多相关文章

  1. HDU 3001 Travelling:TSP(旅行商)【节点最多经过2次】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题意: 有n个城市,m条双向道路,每条道路走一次需要花费路费v.你可以将任意一个城市作为起点出发 ...

  2. HDU 3001 Travelling(状态压缩DP+三进制)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题目大意:有n个城市,m条路,每条路都有一定的花费,可以从任意城市出发,每个城市不能经过两次以上 ...

  3. HDU - 3001 Travelling(三进制状压dp)

    Travelling After coding so many days,Mr Acmer wants to have a good rest.So travelling is the best ch ...

  4. hdu 3001 Travelling(状态压缩 三进制)

    Travelling Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  5. hdu 3001 Travelling (三进制)【状压dp】

    <题目链接> 题目大意: 给出n个点和m条边,求经过所有点所需的最小花费,每个点最多经过两次. 解题分析: TSP问题类型,由于此题每个点有三种状态,所以采用三进制状态压缩,0.1.2 分 ...

  6. HDU 3001 Travelling (状压DP,3进制)

    题意: 给出n<=10个点,有m条边的无向图.问:可以从任意点出发,至多经过同一个点2次,遍历所有点的最小费用? 思路: 本题就是要卡你的内存,由于至多可经过同一个点2次,所以只能用3进制来表示 ...

  7. HDU 3001 Travelling 3进制状压dp

    题意:10个点,若干条边,边有花费,每个点最多走两次,求走过所有点,花费最少 分析:因为每个点最多走两次,所以联想到3进制,然后枚举状态,就行了(我也是照着网上大神的代码写的) #include &l ...

  8. HDU - 3001 Travelling 状压dp + 三进制 [kuangbin带你飞]专题二

    终于刷完搜索专题了. 题意:给定n个城市,每个城市参观不能超过两次,两个城市之间有道路通过需要花费X,求通过能所有城市的最小花费. 思路:每个城市有三个状态0,1,2,可用三进制存储所有城市的访问状态 ...

  9. Hdu 3001 Travelling 状态DP

    题目大意 一次旅游,经过所有城市至少一次,并且任何一座城市访问的次数不能超过两次,求最小费用 每个城市最多访问两次,用状态0,1,2标识访问次数 把城市1~N的状态按照次序连接在一起,就组成了一个三进 ...

随机推荐

  1. python学习笔记之一:列表与元组

    最近在看<python基础教程>(基于python2.x),下面总结一下第二章列表与元组的知识: 在这章中引入了数据结构的概念.数据结构是通过某种方式组织在一起的数据元素的集合.在pyth ...

  2. swift学习笔记(六)析关闭过程和使用分配给属性的默认值

    一.通过关闭和功能的默认实现财产值 当存储属性默认值需要定制,能为客户提供通过关闭或全局函数的自定义默认值. 注意:全局函数的结构,和枚举使用keywordstatic大喊    用classkeyw ...

  3. Ubuntu14.04 用 CrossOver 安装 TMQQ2013

    Crossover 是 wine 的优化+商业版本号 ,  免去了wine的繁琐配置,让Ubuntu安装windows软件很easy..... 部分移植的软件还有官方的维护,执行效果也比較好..... ...

  4. 我的CSDN之路

    经营CSDN博客刚满一年,能够说CSDN给我们带来了非常大的帮助,这一年里CSDN见证了我们的成长.以下两篇博客就是我这一年在CSDN的缩影. 这篇是我一年前写的,那时候刚申请CSDN不久:http: ...

  5. PM俱乐部之旅7-弱活着

     有些人认为,最终我们放松一点时间,有意想不到的事情发生--公司组织结构调整. 公司由于业务范围调整,所以要进行对应的组织结构调整.PMO部门也随之重组,项目经理俱乐部的活动改成项目交流会,请项目 ...

  6. 解决Ubuntu和Windows该文件乱码问题

    1.转换文件内容编码    Windows在自然纯文本文件.当中国作为编码GBK,在Ubuntu下乱码,可以使用iconv命令转换:    iconv -f gbk -t utf8 source_fi ...

  7. CentOS6.5 Nginx优化编译配置

    说到Nginx,它真的算是我在运维工作中的好朋友,它优异的性能和极高的工作效率实在是让人大爱,来自internet的报告称其epoll模型能够支持高达50000个并发连接数. Epoll[维基百科]: ...

  8. Linux System Programming note 8 ——File and Directory Management

    1. The Stat Family #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> ...

  9. Threejs 它可以在建立其内部房间效果可见

    Threejs 中建立可看到其内部的房间效果 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协 ...

  10. 同TextView在不同的显示内容

    首先,请原谅我不能命名文章.. . 我们不能准确地表达你说说什么什么,真正急着赶智商. 直接在地图上 如图所看到的显示的是两个textview 第一个实现的是,在同一个textview中给不同内容赋予 ...