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. iOS Dev (59) 高度自适应的UITextView

    iOS Dev (59) 高度自适应的UITextView 作者:阿锐 地址:http://blog.csdn.net/prevention - 例如以下 _inputTextView 为一个 UIT ...

  2. oracle 转 mysql 最新有效法(转)

    关键字:Oracle 转 MySQL . Oracle TO MySQL 没事试用了一下Navicat家族的新产品Navicat Premium,他集 Oracle.MySQL和PostgreSQL管 ...

  3. mongodb笔记2

    成功启动MongoDB后,再打开一个命令行窗口输入mongo,就可以进行数据库的一些操作. 输入help可以看到基本操作命令: show dbs:显示数据库列表 show collections:显示 ...

  4. With As 获取 id parentId 递归获取所有

    Declare @Id Int  Set @Id = 5;    ---在此修改父节点    With RootNodeCTE(Id,ParentId)  As  (  Select Id,Paren ...

  5. ubuntu 14.04设备OVS虚拟OpenFlow交换机配置汇总

    一.设备OVS sudo apt-get install openvswitch-controller openvswitch-switch openvswitch-datapath-source ( ...

  6. play framework2.5.

    play framework2 的学习笔记 https://github.com/playframework/playframework https://github.com/playframewor ...

  7. simple factory, factory method, abstract factory

    simple factory good:1 devide implementation and initialization2 use config file can make system more ...

  8. WPF/Silverlight中图形的平移,缩放,旋转,倾斜变换演示

    原文:WPF/Silverlight中图形的平移,缩放,旋转,倾斜变换演示 为方便描述, 这里仅以正方形来做演示, 其他图形从略. 运行时效果图:XAML代码:// Transform.XAML< ...

  9. iOS 真机调试(最具体的步骤来解决历史,hmt精心打造)

    /*************************************************************1************************************* ...

  10. Swing-email(转)

    项目结构: 运行效果: 如果你感兴趣,请不要那我的邮箱做测试!!!! ========================================================== 下面是代码部 ...