Boring Assignment Expressions

版权声明:版权所有,转载请标明博文出处。 https://blog.csdn.net/HQG_AC/article/details/85556554

Boring Assignment Expressions 题解

【题意】

一些表达式,有些是直接赋值式,另外一些则是表达式,请你按照一些排列顺序放置,使得所有变量的值之和最小(哦对还有只有+号和*号)

【分析】

一句话题解:字符串处理+拓扑排序(类最短路)

真的是一眼看出怎么做。

想想10分钟,Coding10小时,(10小时都不一定够,,滑稽

【细节】

细节是真心多啊。

看代码吧

【代码】

#include <map>
#include <set>
#include <ctime>
#include <queue>
#include <stack>
#include <cmath>
#include <vector>
#include <bitset>
#include <cstdio>
#include <cctype>
#include <string>
#include <cstring>
#include <cassert>
#include <climits>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <functional>
using namespace std ;
#define rep(i, a, b) for (int (i) = (a); (i) <= (b); (i)++)
#define per(i, a, b) for (int (i) = (a); (i) >= (b); (i)--)
#define clr(a) memset(a, 0, sizeof(a))
#define ass(a, sum) memset(a, sum, sizeof(a))
#define lowbit(x) (x & -x)
#define mp make_pair
#define pb push_back
#define pob pop_back
#define fi first
#define se second
#define enter cout << endl
#define siz(x) ((int)x.size())
typedef unsigned long long ll ;
typedef vector <int> vi ;
typedef pair <int, int> pii ;
typedef map <int, int> mii ;
typedef map <string, int> msi ;
const int N = 100010 ;
const int INF = 0x3f3f3f3f ;
const int iinf = INT_MAX ;
const ll linf = 2e18 ;
const int MOD = 1000000007 ;
void print(int x) { cout << x << endl ; exit(0) ; }
void PRINT(string x) { cout << x << endl ; exit(0) ; }
void douout(double x){ printf("%lf\n", x + 0.0000000001) ; }

vector <string> vexp ; // 所有的表达式, 是去掉 "A = " 的
vector <string> vvar ; // 每个表达式的对应的变量
map <string, ll> vals ; // 变量对应的值
map <string, string> expr ; // 变量对应的表达式
vector <set<string> > vreq ; // 表达式中出现了哪些待定的变量
map <string, vector<int> > vidx ; // 每个变量在哪些表达式中出现
multimap <ll, int> q ; // (val,i)表示i号表达式的变量的值为val
bool bad ; ll ans ; // 总答案
vector <int> res ; // 存储哪些编号的表达式是答案
int n ;

// 处理表达式
ll eval(string s) {
	vector <ll> vv(0) ;
	vector <char> op(0) ;
	istringstream iss(s) ;
	string buf ;
	while (iss >> buf) {
		if (buf == "(") continue ;
		else if (buf == "+") op.pb('+') ;
		else if (buf == "*") op.pb('*') ;
		else if (isdigit(buf[0])) vv.pb(atoi(buf.c_str())) ;
		else if (isalpha(buf[0])) vv.pb(vals[buf]) ;
		else if (buf == ")") {
			ll x = vv.back() ; vv.pob() ;
			ll y = vv.back() ;
			if (op.back() == '+') {
				vv.back() += x ;
				if (vv.back() < x || vv.back() < y) return 0 ;
				// 只有溢出才会是答案比之前都要小
			}
			else if (op.back() == '*') {
				vv.back() *= x ;
				if (vv.back() / x != y) return 0 ; // 同理
			}
			op.pob() ;
		}
		else while (1) cout << "OLE!" ;
	}
	return vv.back() ;
}

void init() {
	vexp.clear() ; vvar.clear() ;
	vals.clear() ; expr.clear() ;
	vreq.assign(n, set<string>()) ;
	vidx.clear() ; q.clear() ;
	bad = false ; ans = 0 ;
	res.clear() ;
}

signed main(){
    while (cin >> n >> ws) {
    	init() ; // 对所有数组清零
    	
    	for (int i = 0; i < n; i++) { // 分别处理每一条表达式
    		string s ;
    		getline(cin, s) ;
    		int p = s.find(' ') ;
    		vvar.pb(s.substr(0, p)) ;
    		vexp.pb(s.substr(p + 3)) ;
			istringstream iss(vexp.back()) ;
			string v ;
			while (iss >> v) {
				if (isalpha(v[0])) {
					vals[v] = 0 ; // 初始, 表示变量
					expr[v] = "" ;
					vreq[i].insert(v) ; // 表达式i中出现了这个变量,重复就算了
					if (siz(vidx[v]) == 0 || vidx[v].back() != i)
					vidx[v].pb(i) ; // 变量->表达式,避免重复丢进
				}
			}
            if (siz(vreq[i]) == 0) { // 表达式形如 A = 3,没有限制,丢入队列中
            	ll val = eval(vexp.back()) ;
            	q.insert(mp(val, i)) ; // 表示i号表达式的变量的值为val
			}
		}
		
		while (!q.empty()) { // DAG上跑类最短路
			ll val = q.begin()->first ; int i = q.begin()->second ;
			q.erase(q.begin()) ;
			string v = vvar[i] ;
			if (vals[v] == 0) {
				res.pb(i) ;
				vals[v] = val ;
				expr[v] = vexp[i] ; // 该变量的表达式被确定
				for (int j = 0; j < siz(vidx[v]); j++) { // 给变量去更新其他表达式
					int k = vidx[v][j] ;
					vreq[k].erase(v) ;
					if (vreq[k].empty()) { // 该表达式所有变量都已经确定
						ll val = eval(vexp[k]) ;
						if (val != 0) q.insert(mp(val, k)) ; // 必须满足合法(及不会溢出)
					}
				}
			}
		}
		
		if (siz(res) < siz(vals)) bad = true ; // 判断答案合法
		// 每个变量初始都有一个值(0),如果结果小于siz(vals),则说明不是解出了所有的值
		for (map <string, ll>::iterator it = vals.begin(); it != vals.end(); it++) {
			if (ans + it->second < ans) {
				bad = true ; // 总答案溢出了
				break ;
			}
			ans += it->second ;
		}
		
		if (bad) cout << "stupid expressions!\n" ;
		else {
			cout << ans << endl ;
			for (int i = 0; i < siz(res); i++) { // 答案本身在存储时就是有序的
				int j = res[i] ;
				cout << vvar[j] << " = " << vexp[j] << endl ;
			}
		}
	}
	return 0 ;
}

/*
写代码时请注意:
	1.ll?数组大小,边界?数据范围?
	2.精度?
	3.特判?
	4.至少做一些
思考提醒:
	1.最大值最小->二分?
	2.可以贪心么?不行dp可以么
	3.可以优化么
	4.维护区间用什么数据结构?
	5.统计方案是用dp?模了么?
*/

猜你喜欢

转载自blog.csdn.net/HQG_AC/article/details/85556554
今日推荐