zoukankan      html  css  js  c++  java
  • HDU 4921 Map(状态压缩)

    题意看这篇博客

    思路参考的这篇博客

    补充:面对这种问题有一个常见的套路。比如计算若干个区间对答案的贡献这种问题,直接暴力可能复杂度到O(n ^ 2), 而我们可以计算出每个元素在多少个合法区间中,然后计算贡献,这样可以降到O(n)。对于此题,计算第一类贡献时就是这种方法。计算有多少种情况包含了这个元素,这样就算出了这种元素对第一种答案的贡献。有一个坑点需要注意,在读入每条边x, y时,必选立刻标记y已经访问过,这样最后没被标记过的就是链头。如果不提前标记,从前往后扫描时第一次遇到的没标记的点不一定是链头。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 10010;
    int tot;
    int Next[maxn], now[15], len[15];
    bool v[maxn];
    int val[maxn];
    int main() {
    	int T, x, y, n, m;
    	scanf("%d", &T);
    	double res, ans, sum, method;
    	bool flag;
    	int num;
    	while(T--) {
    		scanf("%d%d", &n, &m);
    		memset(v, 0, sizeof(v));
    		memset(Next, 0, sizeof(Next));
    		memset(len, 0, sizeof(len));
    		memset(now, 0, sizeof(now));
    		tot = 0;
    		res = 1;
    		ans = 0;
    		for (int i = 1; i <= n; i++) {
    			scanf("%d", &val[i]);
    		}
    		for (int i = 1; i <= m; i++) {
    			scanf("%d%d", &x, &y);
    			x++, y++;
    			Next[x] = y;
    			v[y] = 1;
    		}
    		for (int i = 1; i <= n; i++) {
    			if(v[i]) continue;
    			now[tot] = i;
    			for (int j = i; j; j = Next[j]) {
    				len[tot]++;
    			}
    			res *= len[tot] + 1;
    			tot++;
    		}
    		for (int dep = 1;; dep++) {
    			int cnt = 0;
    			for (int i = 0; i < tot; i++) {
    				if(now[i])
    					cnt++;
    			}
    			if(cnt == 0) break;
    			for (int i = 1; i < (1 << tot); i++) {
    				num = 0;
    				sum = 0, method = 1; 
    				flag = 0;
    				for (int j = 0; j < tot; j++) {
    					if((i >> j) & 1) {
    						if(!now[j]) {
    							flag = 1;
    							break;
    						}
    						num++;
    						sum += val[now[j]];
    						method *= (len[j] - dep + 1);
    					} else {
    						method *= min(dep, len[j] + 1);
    					}
    				}
    				if(!flag) {
    					ans += method * sum;
    					if(num > 1)
    						ans += method * sum * num / cnt;
    				}
    			}
    			for (int i = 0; i < tot; i++)
    				now[i] = Next[now[i]];
    		}
    		printf("%.3f
    ", ans / (res - 1));
    	}
    } 
    

      

  • 相关阅读:
    直接初始化和复制初始化
    C++ 内连接与外连接 (转)
    mysql-Innodb事务隔离级别-repeatable read详解(转)
    Linux操作系统多线程信号总结
    Keil MDK 5.14 仿真时System Viewer菜单显示空白和Peripherals菜单无外设寄存器
    转载傅里叶级数和傅里叶变换的理解 https://www.cnblogs.com/h2zZhou/p/8405717.html
    SPI总线的原理与Verilog实现
    SD 模拟sip 读写子程序
    SD卡 模拟SPI总线控制流程
    SD卡spi读写流程
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10553619.html
Copyright © 2011-2022 走看看