zoukankan      html  css  js  c++  java
  • hdu 3001 Travelling(状态压缩 三进制)

    Travelling

    Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 6600    Accepted Submission(s): 2144


    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
     
    Source
     
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #define M 25
    #define INF 0x1f1f1f1f
    #define N 65000
    using namespace std;
    int n,m;
    int state[M]={0,1,3,9,27,81,243,729,2187,6561,19683,59049};//state[i]表示第i个点城市状态用3进制表示是多少
    int dis[N][M];//dis[i][j]表示i状态j点走过几次
    int dp[N][M];//dp[i][j]表示第i个状态最后到达j的最小距离
    int g[M][M];//表示两点间的距离
    /*
    寻找最短路径用了floyd算法的原理,求两个点之前的最短距离,不断寻找中间点来缩小权值;
    状态转移:遍历所有的三进制状态,找到上一个状态(第j个城市没去过的或者去过一次的)然后转移到这个状态j位置上加一的状态上,但是能不能转移
    要看本次转移是不是会缩短时间
    */
    int main()
    {
        //freopen("in.txt","r",stdin);
    	for(int i=0;i<59050;i++)
    	{
    		int x=i;
    		for(int j=1;j<=10;j++)//最多有十位
    		{
    			dis[i][j]=x%3;
    			x/=3;
    			if(x==0)
    				break;
    			//cout<<j<<endl;
    		}
    		//cout<<i<<endl;
    	}//初始化第i个状态的j位上的数是几
    	while(scanf("%d%d",&n,&m)!=EOF)
    	{
    		int a,b,c;
    		memset(g,INF,sizeof g);
    		for(int i=0;i<m;i++)
    		{
    			scanf("%d%d%d",&a,&b,&c);
    			if(c<g[a][b])
    				g[a][b]=g[b][a]=c;
    		}//处理输入
    		memset(dp,INF,sizeof dp);
    		int tol=pow(3.0,n);
    		for(int i=1;i<=n;i++) dp[state[i]][i]=0;//初始化从最后到达i城市最小距离的这个状态转移到i城市需要的最小时间就是0;
    		int cur=INF;
    		//下面求最短路径的原理是floyd算法(两个点之间不断寻找中间点来缩小权值)
    		for(int i=0;i<tol;i++)//枚举所有可能的状态
    		{
    			int flag=1;;//用于判断当前状态是不是没走
    			for(int j=1;j<=n;j++)//枚举你需要找的中间过程的城市
    			{
    				if(dis[i][j]==0) flag=0;//判断这个是不是
    				if(dp[i][j]==INF) continue;
    					//cout<<"dis[i][j]="<<dis[i][j]<<endl;
    				for(int k=1;k<=n;k++)//枚举当前当前状态(就是你要转移到的状态)
    				{
    					if(j==k) continue;
    					// cout<<"come in"<<endl;
    					if(g[j][k]!=INF&&dis[i][k]<2)//从j到k的道路是通的,并且在这个状态中k点经过的次数不到两次
    					{
    						int newstate=i+state[k];//新的状态就是走到这个城市,给k点经过的次数加一
    						dp[newstate][k]=min(dp[newstate][k],dp[i][j]+g[j][k]);
    					}
    					
    					// cout<<"dp[newstate][k]="<<dp[newstate][k]<<endl;
    				}
    				//cout<<j<<endl;
    			}
    			if(flag)
    				for(int j=1;j<=n;j++)
    					cur=min(dp[i][j],cur);
    		}
    		if(cur==INF)//如果取到正无穷就是那么没有联通路所以就不可能走完
    			puts("-1");
    		else
    			printf("%d
    ",cur);
    	}
       return 0;
    }
    

      

  • 相关阅读:
    未知高度、宽度,垂直水平居中
    js千分位处理
    浮动与两侧皆自适应布局
    html5 canvas 学习笔记(一)
    全面理解javascript的caller,callee,call,apply概念[转载]
    cocos2dx android运行Luac编译后的lua代码
    cocos2dx android lua文件设置问题
    cocos2dx android resources.ap_ does not exist
    Gink掉过的坑(一):将CCTableView导入到lua中
    数据结构之内部排序个人总结
  • 原文地址:https://www.cnblogs.com/wuwangchuxin0924/p/5744184.html
Copyright © 2011-2022 走看看