记录编号 |
104149 |
评测结果 |
AAAAAAAAAA |
题目名称 |
[NOI 1998]并行计算 |
最终得分 |
100 |
用户昵称 |
cstdio |
是否通过 |
通过 |
代码语言 |
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;
}