记录编号 104149 评测结果 AAAAAAAAAA
题目名称 [NOI 1998]并行计算 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 0.095 s
提交时间 2014-06-03 11:52:32 内存使用 0.40 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int kase=0;
const int SIZEP=1010,SIZEL=310,INF=0x7fffffff/2;
const int REP=1000;
int random(int x,int y){
	return rand()%(y-x+1)+x;
}
int T[5]={0};//操作用时
string expre;//表达式
int matchbk[SIZEL]={0};//第i位的右括号匹配的左括号位置
int letternum=0,letteraddr[SIZEL]={0};//ascii为i的字母所对应起始地址
class NODE{
public:
	NODE *lmson,*left,*right,*father;//最左儿子,左兄弟,右兄弟,父亲
	char val;//加减为1,乘除为2,字母就是字母
	int ftim,addr,op;//完成时间,地址,对上级的贡献
	int id;//一个唯一编号,对应在tree数组中的位置
	void print(void){
		printf("id: %d\nval: %c\nftim: %d\naddr: %d\nop: %d\n",id,val,ftim,addr,op);
		printf("lmson: %d\nleft: %d\nright: %d\n\n",lmson->id,left->id,right->id);
	}
};
int tot=0;
NODE *Nil;
NODE tree[SIZEP]={0},*root;
void printtree(NODE *x){
	x->print();
	for(NODE *t=x->lmson;t!=Nil;t=t->right) printtree(t);
}
vector<NODE*> leaves;
void eraseleaf(NODE *x){leaves.erase(find(leaves.begin(),leaves.end(),x));}
NODE* newNODE(void){
	tree[tot].lmson=tree[tot].left=tree[tot].right=tree[tot].father=Nil;
	tree[tot].id=tot;
	tree[tot].val=tree[tot].ftim=tree[tot].addr=tree[tot].op=0;
	return &tree[tot++];
}
bool singlechild(NODE *x){
	if(x==Nil) return false;
	return x->lmson->right==Nil;
}
class ORDER{
public:
	int tim,alu,op,a1,a2,a3;
	void print(void){printf("OP %d %d %d %d %d %d\n",tim,alu,op,a1,a2,a3);}
};
class SOLUTION{
public:
	ORDER C[SIZEP];//命令
	int endtim,endaddr,cnt;//终止时间,终止地址,命令数
};
SOLUTION nowsol,bestsol;
void answer(void){
	for(int i=1;i<=bestsol.cnt;i++) bestsol.C[i].print();
	printf("END %d %d\n",bestsol.endtim,bestsol.endaddr);
}
int ALU_tim[5]={0};//两个运算器的运算时间
int memtot=0;//寄存器到哪了
void find_ab(NODE* &a,NODE* &b){//找到可以合并的两个点a,b
	bool visit[SIZEP]={0};//是否曾尝试过合并这个点的两个儿子
	vector<NODE*> nowson;
	while(true){
		nowson.clear();
		NODE *x=leaves[random(0,leaves.size()-1)]->father;
		if(visit[x->id]) continue;
		visit[x->id]=true;
		for(NODE* t=x->lmson;t!=Nil;t=t->right){
			if(t->addr>0) nowson.push_back(t);//如果它已经被计算出来
		}
		if(nowson.size()<2) continue;
		int p=random(0,nowson.size()-1),q=random(0,nowson.size()-2);
		if(q>=p) q++;
		if(q<p) swap(p,q);
		a=nowson[p],b=nowson[q];
		break;
	}
}
void deal(NODE *a,NODE *b){//计算并将这两个点合起来
	int r=(ALU_tim[1]<=ALU_tim[2])?1:2;
	if(a->ftim>ALU_tim[r]||b->ftim>ALU_tim[r]) r=3-r;//不能让运算器等数
	nowsol.C[++nowsol.cnt]=(ORDER){ALU_tim[r],r,b->op,a->addr,b->addr,++memtot};
	ALU_tim[r]+=T[b->op];
	//把b去掉,修改a
	a->ftim=ALU_tim[r];
	a->addr=memtot;
	b->left->right=b->right;
	b->right->left=b->left;
	eraseleaf(b);
	while(singlechild(a->father)){//用a去代替它的父亲
		//显然,a的父亲在树中的悬挂方式并不改变
		a->father->ftim=a->ftim,a->father->addr=a->addr;
		a->father->lmson=Nil;
		eraseleaf(a);
		leaves.push_back(a->father);
	}
}
void singlestep(void){
	NODE *a,*b;
	find_ab(a,b);
	deal(a,b);
}
int opcode(char x){
	if(x=='+') return 1;
	if(x=='-') return 2;
	if(x=='*') return 3;
	if(x=='/') return 4;
	return INF;
}
int getlevel(int x){//12(+-)是第一级,34(*/)是第二级
	return (x+1)/2;
}
NODE* maketree(int l,int r){
	//cout<<l<<" "<<r<<" "<<tot<<endl;
	NODE *p=newNODE();
	if(l==r){//这是一个字母
		p->val=expre[l];//值就是当前字母
		p->ftim=0,p->addr=letteraddr[p->val];
		leaves.push_back(p);
		return p;
	}
	while(l<r&&expre[r]==')'&&matchbk[r]==l){
		l++,r--;
	}
	int minlev=INF;
	for(int i=r;i>=l;i--){
		if(expre[i]==')') i=matchbk[i];
		minlev=min(minlev,getlevel(opcode(expre[i])));//如果expre[i]并非操作符,那么getlevel就返回一个大数
	}
	p->val=minlev+'0';//1就是1,2就是2
	int i=r,j=r;
	while(i>=l){
		if(expre[i]==')') i=matchbk[i];
		if(getlevel(opcode(expre[i]))==minlev){//从i+1到j
			NODE *t=maketree(i+1,j);
			t->op=opcode(expre[i]);
			t->father=p;
			t->right=p->lmson,p->lmson->left=t;
			p->lmson=t;
			j=i-1;
		}
		i--;
	}
	NODE *t=maketree(l,j);
	t->op=minlev*2-1;//如果是一级运算就是+,二级运算就是*
	t->father=p;
	t->right=p->lmson,p->lmson->left=t;
	p->lmson=t;
	return p;
}
void maketree(void){
	leaves.clear();
	tot=0;
	root=maketree(0,expre.size()-1);
	root->father=Nil;
}
void greedy_test(void){
	nowsol.cnt=0;
	memset(ALU_tim,0,sizeof(ALU_tim));
	memtot=letternum;
	maketree();
	while(leaves.size()>=2)	singlestep();
	nowsol.endtim=max(ALU_tim[1],ALU_tim[2]);
	nowsol.endaddr=memtot;
	if(nowsol.endtim<bestsol.endtim) bestsol=nowsol;
}
void init(void){
	Nil=new NODE;Nil->id=-1;
	for(int i=1;i<=4;i++) scanf("%d",&T[i]);
	cin>>expre;
	vector<int> st;
	bool letterused[SIZEL]={0};//字母是否用过,以决定初始地址
	for(int i=0;i<expre.size();i++){
		letterused[expre[i]]=true;
		if(expre[i]=='(') st.push_back(i);
		else if(expre[i]==')'){
			matchbk[i]=st.back();
			st.pop_back();
		}
	}
	for(int i='A';i<='Z';i++) if(letterused[i]) letteraddr[i]=++letternum;
	bestsol.endtim=INF;
}
int main(){
	freopen("parallel.in","r",stdin);
	freopen("parallel.out","w",stdout);
	srand(2);//用这个种子就能过了,其他的种子有可能得90
	init();
	for(int i=1;i<=REP;i++){
		kase=i;
		greedy_test();
	}
	answer();
	return 0;
}