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. hdu 5073 Galaxy(2014acm鞍山亚洲分部 C)

    主题链接:http://acm.hdu.edu.cn/showproblem.php? pid=5073 Galaxy Time Limit: 2000/1000 MS (Java/Others)   ...

  2. Android下的单元測试

    android下的单元測试 在AndroidManifest.xml文件里配置下面信息: 在manifest节点下加入: <!-- 指定測试信息和要測试的包 --> <instrum ...

  3. Ubuntu下安装vmware 9.0 + 注册码

    先附上一些注册码到时使用: NA0UF-DUH00-QZHM0-MU17K-CC824 4F469-F024Q-CZ8R9-DL1N0-13C6W HF261-0HL40-FZX21-F9AQ2-0C ...

  4. Visual C++学习笔记1:一定要注意ANSI和UNICODE差额

    最近的研究VC++.下载VS2013,根据<Visual C++开发实战系列>首先hello我写了一个常规样品,结果显示乱码编辑框.夜已经折腾型转变.然后总结很明显ANSI和UNICODE ...

  5. jrtplib使用注意事项

    一.说明 RTP 现在的问题是要解决的流媒体的实时传输的问题的最佳方法.和JRTPLIB 是一个用C++语言实现的RTP库.包含UDP通讯.刚使用JRTPLIB,对JRTPLIB的理解还不够深,当做使 ...

  6. Cocos2d-x学习笔记(19)(TestCpp源代码分析-3)

    本章主要介绍testBasic.h/cpp,这两个文件主要用于返回主场景界面. //testBasic.h #ifndef _TEST_BASIC_H_ #define _TEST_BASIC_H_ ...

  7. [Eclipse]代码已被写入关于如何切换到unix在新行

    切换换行符的显示格式, 一般的设置是这种: 可是这样仅仅能对新文件起作用,原来已经写好的还是那熊样.(怎么办呢,得吃懊悔药啊,谁让你開始没准备好呢?!T_T) 以下就是懊悔药: 这样就OK了. 附:有 ...

  8. CareerCup Chapter 4 Trees and Graphs

    struct TreeNode{ int val; TreeNode* left; TreeNode* right; TreeNode(int val):val(val),left(NULL),rig ...

  9. iis6开户gzip 网站属性里面没有服务选项卡

    请注意一点,是直接在名为“网站”的文件夹上面右键选择属性,不是去点下面建立的某一个网站.开户GZIP是整台服务器上面的虚拟主机都同时开启的,不对针某一个单独网站. 开启Gzip具体步骤: 1. 在 & ...

  10. grep在一个特定的文件搜索文件夹keyword

    grep -R --include="*.*"(文件名匹配)  key(keyword) dir(夹) eg.在当前文件夹搜索xml关键文件172.19.32.22 grep -R ...