zoukankan      html  css  js  c++  java
  • poj 2288 Islands and Bridges (状压dp+Tsp问题)

    这道题千辛万苦啊!

    这道题要涉及到当前点和前面两个点,那就设dp[state][i][j]为当前状态为state,当前点为i,前一个点为j

    这个状态表示和之前做炮兵那题很像,就是涉及到三个点时,就多设一维表示前一个点(炮兵那题把点换成行)

    这道题有很多细节需要注意

    (1)计算路径长度。这道题一开始怎么不重复又方便的计算长度难住了我。

    后来看到题解直接在初始化的时候算上路径,非常牛逼

    然后前两个点的路径就包含进去了。

    首先加上前一个点和当前点的价值

    然后看有没有构成三角形,有就再加上

    (2)更新答案。这里更新答案要dp完了之后再弄,在dp时更新会出错

    多打几行代码不会死的,重要是要ac,麻烦一点就麻烦一点

    (3)初始化问题。这里谈谈填表法和刷表法初始化的不同

    如果是刷表法,那么就不知道当前状态合不合理,那就每次都需要判断一下

    一般来说一开始全部初始化为-1表示全部不合理,然后就把一开始合理的部分(比如起点)赋初值(一般为0)。

    如果是填表法的话,一般来说不需要判断合不合理

    但是这道题不一样,并不知道前两个点的状态是否合法,所以需要判断。

    (4)这道题有个比较坑的地方,就是n=1时要特判

    (5)然后自己头脑一定要清楚哪一个变量是第几个点!!

    我一般是写i是当前点,j是前一个点,k是前前个点

    (6)下标范围是0到n-1,那么就写1 << n

    (7)方案数。这道题方案数最后要除以2,因为可以反着走,但题目里算同一种

    然后dp弄方案一般可以开一个数组,意义是和dp数组一模一样的,只不过存的是方案数

    然后符合就加上

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define REP(i, a, b) for(int i = (a); i < (b); i++) 
    #define _for(i, a, b) for(int i = (a); i <= (b); i++) 
    using namespace std;
    
    typedef long long ll;
    const int MAXN = 15;
    int dp[(1 << 13) + 10][MAXN][MAXN], w[MAXN];
    int g[MAXN][MAXN], n, m; 
    ll ways[(1 << 13) + 10][MAXN][MAXN];
    
    int main()
    {
    	int T;
    	scanf("%d", &T);
    	
    	while(T--)
    	{
    		memset(g, 0, sizeof(g));
    		memset(dp, -1, sizeof(dp)); //初始化要注意 
    		memset(ways, 0, sizeof(ways));
    		
    		scanf("%d%d", &n, &m);
    		REP(i, 0, n) scanf("%d", &w[i]);
    		while(m--)
    		{
    			int u, v;
    			scanf("%d%d", &u, &v); u--; v--;
    			g[u][v] = g[v][u] = 1;
    		}
    		
    		if(n == 1) { printf("%d 1
    ", w[0]); continue; } //特判 
    		
    		REP(i, 0, n) //初始化 
    			REP(j, 0, n)
    				if(g[i][j])
    				{
    					dp[(1<<i)|(1<<j)][i][j] = w[i] + w[j] + w[i] * w[j];
    					ways[(1<<i)|(1<<j)][i][j] = 1;
    				}
    					
    		REP(S, 0, 1 << n)
    		  REP(i, 0, n) if(S & (1 << i))
    			REP(j, 0, n) if((S & (1 << j)) && g[i][j])
    			  REP(k, 0, n) if((S & (1 << k)) && g[j][k])
    			  {
    			  	if(i == j || j == k || i == k || dp[S^(1<<i)][j][k] == -1) continue; 
    			  	ll t = dp[S^(1<<i)][j][k] + w[i] + w[j] * w[i]; // 注意这里哪一个是最后一点 
    			  	if(g[i][k]) t += w[i] * w[j] * w[k];
    				   
    				if(dp[S][i][j] < t)
    				{
    					dp[S][i][j] = t;
    					ways[S][i][j] = ways[S^(1<<i)][j][k];
    				}
    				else if(dp[S][i][j] == t) ways[S][i][j] += ways[S^(1<<i)][j][k]; //这里是else if 写if会错 
    			  }
    		
    		ll ans = 0, num = 0; //分开来做 
    		int S = (1 << n) - 1;
    		REP(i, 0, n)
    			REP(j, 0, n)
    				if(g[i][j])
    				{
    					if(ans < dp[S][i][j])
    					{
    						ans = dp[S][i][j];
    						num = ways[S][i][j];
    					}
    					else if(ans == dp[S][i][j])
    						num += ways[S][i][j];
    				}
    		printf("%lld %lld
    ", ans, num / 2);
    	}
    		
    	return 0;
    }
  • 相关阅读:
    WCF 第八章 安全 确定替代身份(中)使用AzMan认证
    WCF 第八章 安全 总结
    WCF 第八章 安全 因特网上的安全服务(下) 其他认证模式
    WCF Membership Provider
    WCF 第八章 安全 确定替代身份(下)模仿用户
    WCF 第八章 安全 因特网上的安全服务(上)
    WCF 第九章 诊断
    HTTPS的七个误解(转载)
    WCF 第八章 安全 日志和审计
    基于比较的排序算法集
  • 原文地址:https://www.cnblogs.com/sugewud/p/9819326.html
Copyright © 2011-2022 走看看