现在的位置: 首页 > 综合 > 正文

UVA – 1354(指针结点的联合方法 || 高效算法复杂度未算出)

2019年04月05日 ⁄ 综合 ⁄ 共 3251字 ⁄ 字号 评论关闭

指针结点联合,即每个指针指向一个实际node,联合申请一个新node,并用一个新指针代表它;

#include<cstdio>
#include<cstring>
#include<cctype>
#include<queue>
#include <vector>
#include <iostream>
using namespace std;

const int maxn = 7;
typedef struct node *pointer;
struct node{
double weight,leftw,rightw,zhong;
node *left,*right;
node():left(NULL),right(NULL){}
};
int n;
double w[maxn],r;
double res=-1;

double cal_wei(pointer root,int floor){
if(root->left==NULL&&root->right==NULL){
    root->leftw=root->rightw=0;
    return root->weight;
}
    root->leftw=cal_wei(root->left,floor+1);
    root->rightw=cal_wei(root->right,floor+1);
    return root->leftw+root->rightw;
}

double Min,Max;
void cal_posi(pointer root){
if(root->left==NULL&&root->right==NULL){
        return ;
}
root->left->zhong=root->zhong-root->rightw/(root->rightw+root->leftw);
root->right->zhong=root->leftw/(root->rightw+root->leftw)+root->zhong;
Max=max(Max,root->right->zhong);
Min=min(Min,root->left->zhong);
cal_posi(root->left); cal_posi(root->right);
}
void dfs(int num,vector<pointer>& now){
if(num==1){
     cal_wei(now[0],0);
     now[0]->zhong=0;
     Min=10000; Max=-10000;
     cal_posi(now[0]);
     if(Max-Min>=0&&Max-Min<=r){
        res=max(res,Max-Min);
     }
     return ;
}

<pre name="code" class="html">//对本题而言,此解为朴素算法;
for(int i=0;i<num;i++)
 for(int j=0;j<num;j++) if(i!=j){    //最坏复杂度分析, (6*5)*(5*4)*(4*3)*(3*2)*(2*1)*6*10*2 = 10368000;
     vector<pointer> next;        //  临时变量的位置特别重要;该句子放在循环外将导致每次没有消除dfs影响
     pointer x=now[i],y=now[j];
     for(int k=0;k<num;k++) if(k!=i&&k!=j) next.push_back(now[k]);
     pointer temp=new node();
     temp->weight=-1; temp->left=x; temp->right=y;
     next.push_back(temp);
     dfs(num-1,next);
}
}
int main()
{
  int T;
  scanf("%d",&T);

  while(T--){
    scanf("%lf %d",&r,&n);
    vector<pointer> ans;
    double x;
    for(int i=1;i<=n;i++){
        scanf("%lf",&x);
        pointer temp=new node();
        temp->weight=x;
        ans.push_back(temp);
    }
    if(n==1) {
        double t=0; printf("%.9lf\n",t); continue;
    }
    res=-1000;
    dfs(n,ans);
    if(res==-1000) printf("-1\n");
    else printf("%.9lf\n",res);
  }
  return 0;
}

下面为高效算法;

用到子集的枚举技巧,node【i】里存的为所有子树姿态下的最优长度;

由于使用

#include <stdio.h>
#include <string.h>
#include <vector>
#define INF 0x3f3f3f3f
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N = 6;
const int MAXN = (1<<N);
int t, n, i, j, vis[MAXN];
double w[N], sumw[MAXN], r;
struct Node {
	double l, r;
	Node() {}
	Node(double ll, double rr) {l = ll; r = rr;}
};
vector<Node> node[MAXN];

int bitcount(int x) {
	if (x == 0) return 0;
	return bitcount(x/2) + (x&1);
}

void dfs(int s) {
	if (vis[s]) return;
	vis[s] = 1;
	if (bitcount(s) == 1) {
		node[s].push_back(Node(0, 0));
		return;
	}
	for (int l = (s - 1)&s ; l > 0; l = (l - 1)&s)  { //非连续1(如11001)的子集枚举方式,循环量(2^(bitcount(s)-2))
		int r = s^l;
		dfs(l); dfs(r);
		for (int i = 0; i < node[l].size(); i++) {
			for (int j = 0; j < node[r].size(); j++) {
				double ll =min(-sumw[r] / (sumw[l] + sumw[r]) + node[l][i].l,sumw[l] / (sumw[l] + sumw[r]) + node[r][j].l);
				double rr =max(sumw[l] / (sumw[l] + sumw[r]) + node[r][j].r,-sumw[r] / (sumw[l] + sumw[r]) + node[l][i].r);
            
   
                                node[s].push_back(Node(ll, rr));
			}
		}
	}
}

void solve() {
	double ans = -1;
	int s = (1<<n) - 1;
	dfs(s); //printf("%d***\n",node[s].size());  node[s].size()代表所有可能的子树的左右最大值或最小值; 
	for (int i = 0; i < node[s].size(); i++) {
		if (node[s][i].r - node[s][i].l < r) {
			if (node[s][i].r - node[s][i].l > ans)
				ans = node[s][i].r - node[s][i].l;
		}
	}
	if (ans == -1) printf("-1\n");
	else printf("%.10lf\n", ans);
}

int main() {
	scanf("%d", &t);
	while (t--) {
		memset(vis, 0, sizeof(vis));
		memset(node, 0, sizeof(node));
		scanf("%lf%d", &r, &n);
		for (i = 0; i < n; i++)
			scanf("%lf", &w[i]);
		for (i = 0; i < (1<<n); i++) {
			sumw[i] = 0;
			for (j = 0; j < n; j++) {
				if (i&(1<<j))
					sumw[i] += w[j];
			}
		} //计算每个子集的重量
		solve();
	}
	return 0;
}

抱歉!评论已关闭.