zoukankan      html  css  js  c++  java
  • 【状压dp】Travelling

    [hdu3001]Travelling

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

    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
     
    Recommend
    gaojie
     
    题目大意:有N个点,M条边,每条边都有权值,每个点不能经过大于两次,问把整个图走完的最小代价。如果不行输出-1。
    试题分析:这题不同于codevs上那道3分钟的TSP水题,这回对于次数有限制。
         考虑2进制,我们发现无法表示它的状态了,那么3进制可行么?
         3进制每位代表访问过这个节点的次数。dp[S][j]表示状态为S,现在在j的最小代价。
         那么dp[S][j]=min(dp[S][j],dp[S-tri[j]][k]+e[k][j]);
         tri[i]表示三进制下长度为i的MAX。
         我们可以先预处理出来3进制每个数每位是什么,然后就好做了。
     
    代码(为什么就我写的是逆推QAQ):
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<algorithm>
    using namespace std;
    
    inline int read(){
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int MAXN=100001;
    const int INF=0x1f1f1f1f;//这里不知道为什么赋值9999999过不了
    const int Max3=59050;
    int tri[12] ={0,1,3,9,27,81,243,729,2187,6561,19683,59049};  
    int N,M;
    int ditk[100001][11];
    int dp[100001][11];
    int e[11][11];
    
    int ans;
    
    int main(){
        memset(ditk,0,sizeof(ditk));
        for(int i=1;i<Max3;i++){
            int tmp=0,x=i;
            while(x){
                ditk[i][++tmp]=x%3;
                x/=3;
                if(x==0) break;
            }
        }
        while(scanf("%d%d",&N,&M)!=EOF){
            ans=INF;
            memset(dp,INF,sizeof(dp));
            memset(e,INF,sizeof(e));
            for(int i=1;i<=M;i++){
                int u=read(),v=read(),w=read();
                e[u][v]=e[v][u]=min(w,e[v][u]);
            }
            for(int i=1;i<=N;i++) dp[tri[i]][i]=0;
            for(int i=1;i<tri[N+1];i++){
                bool k=true;
                for(int j=1;j<=N;j++){
                    if(!dp[i][j]) continue;
                    if(!ditk[i][j]) continue;
                    for(int k=1;k<=N;k++){
                        if(e[k][j]>=INF||ditk[i-tri[j]][j]>=2||k==j||!ditk[i-tri[j]][k]) continue;
                        dp[i][j]=min(dp[i][j],dp[i-tri[j]][k]+e[k][j]);
                    }
                }
            }
            for(int i=1;i<tri[N+1];i++){
                bool k=true;
                for(int j=1;j<=N;j++) if(!ditk[i][j]){
                    k=false; break;
                }
                if(k) for(int j=1;j<=N;j++) ans=min(ans,dp[i][j]);
            }
            if(ans!=INF) printf("%d
    ",ans);
            else puts("-1");
        }
    }
    

    又写了一个顺推:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<algorithm>
    using namespace std;
    
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*f;
    }
    const int MAXN=100001;
    const int INF=0x1f1f1f1f;
    const int Max3=59050;
    int tri[12] ={0,1,3,9,27,81,243,729,2187,6561,19683,59049};  
    int N,M;
    int ditk[100001][11];
    int dp[100001][11];
    int e[11][11];
    
    int main(){
    	memset(ditk,0,sizeof(ditk));
    	for(int i=0;i<Max3;i++){
    	    int tmp=0,x=i;
    		while(x){
    			ditk[i][++tmp]=x%3;
    			x/=3;
    			if(x==0) break;
    		}
    	}
        while(scanf("%d%d",&N,&M)!=EOF){
        	int ans=INF;
    		memset(dp,INF,sizeof(dp));
        	memset(e,INF,sizeof(e));
    		for(int i=1;i<=M;i++){
        		int u=read(),v=read(),w=read();
    			if(w<e[u][v]) e[u][v]=e[v][u]=w;
    		}
    		for(int i=1;i<=N;i++) dp[tri[i]][i]=0;
    		for(int i=0;i<tri[N+1];i++){
    			bool flagt=true;
    			for(int j=1;j<=N;j++){
    				if(!ditk[i][j]) flagt=false;
    				if(dp[i][j]==INF) continue;
    				for(int k=1;k<=N;k++){
    					if(k==j) continue;
    					if(e[j][k]>=INF||ditk[i][k]>=2) continue;
    					dp[i+tri[k]][k]=min(dp[i+tri[k]][k],dp[i][j]+e[j][k]);
    				}
    			}
    			if(flagt){
    				for(int j=1;j<=N;j++) 
    					ans=min(ans,dp[i][j]);
    			}
    		}
    		if(ans==INF) puts("-1");
    		else printf("%d
    ",ans);
    	}
    }
  • 相关阅读:
    ACM
    Java实现排序
    HTML导出Excel文件(兼容IE及所有浏览器)
    WebForm应用log4net记录错误日志——使用线程列队写入
    @RefreshScope 配置方法
    Eclipse oxygen 版本汉化教程
    创建Dynamic Web Project时 显示最新Apache Tomcat 8.0 的方法
    微软汉字转拼音
    Ueditor 前后端分离实现文件上传到独立服务器
    汉字转拼音类(多音字)
  • 原文地址:https://www.cnblogs.com/wxjor/p/7266076.html
Copyright © 2011-2022 走看看