【洛谷 P2656】采蘑菇
2015-10-25 21:10
323 查看
好一次月赛,好一次良(bian)心(tai)的题目
我与靳小才那些不得不说的故事
因为有链接(懒得写),所以我就不上题面了~
这个题目,又是一道精彩的scc模(suan)板(fa)题
嗯,他们想尽可能多拿蘑菇,嗯
那一条边我能走几次走几次,有向图,想走几次走几次……?这是什么,告诉我——SCC!!!!
是的,就是SCC!
显然(其实没那么显然),scc上的边我可以尽可能的多拿走
just like
其中,l是边,v是权值,c是那个double
好的,就是这样,我们把scc上的搞完了
那么其他的呢……?
且慢……
不不不不不不是DAG好烦啊,咱把它搞成个DAG吧
嗯,好主意
来吧
恩恩
ff是记录的
恩恩
所谓……遍历边……?
恩恩
就是这样
但是,缩点之前,我们不妨先求个scc中的ans
要不,叫点权好了
嗯,是个好主意
那么怎么办呢
val,dfs吧
dfs??
枚举
嗯
枚举
对对对
枚举多棒
就是dfs()?
好像是一样呀
本来就应该一样
不过庄周梦蝶罢了
也就是这样了:
然后,接下来是普通的言和 tarjan
最后,跑个spfa什么的就好了
是最长路,最长路哦~~
顺带一提,ans要这样处理
总而言之,嘛
就是这样了
我与靳小才那些不得不说的故事
因为有链接(懒得写),所以我就不上题面了~
这个题目,又是一道精彩的scc模(suan)板(fa)题
嗯,他们想尽可能多拿蘑菇,嗯
那一条边我能走几次走几次,有向图,想走几次走几次……?这是什么,告诉我——SCC!!!!
是的,就是SCC!
显然(其实没那么显然),scc上的边我可以尽可能的多拿走
just like
[code]int get_val(int i) { int ret = l[i].v; int nowval = l[i].v; while(1) { nowval = nowval * l[i].c; if(!nowval) return ret; ret += nowval; } }
其中,l是边,v是权值,c是那个double
好的,就是这样,我们把scc上的搞完了
那么其他的呢……?
且慢……
不不不不不不是DAG好烦啊,咱把它搞成个DAG吧
嗯,好主意
来吧
[code] init(); for(int i = 1;i <= m;i ++) if(scc_num[ff[i]] != scc_num[tt[i]]) build(scc_num[ff[i]],scc_num[tt[i]],vv[i],cc[i]);
恩恩
ff是记录的
恩恩
所谓……遍历边……?
恩恩
就是这样
但是,缩点之前,我们不妨先求个scc中的ans
要不,叫点权好了
嗯,是个好主意
那么怎么办呢
val,dfs吧
dfs??
枚举
嗯
枚举
对对对
枚举多棒
就是dfs()?
好像是一样呀
本来就应该一样
不过庄周梦蝶罢了
也就是这样了:
[code] for(int u = 1;u <= n;u ++) for(int i = first[u];~i;i = next[i]) if(scc_num[u] == scc_num[l[i].t]) val[scc_num[u]] += get_val(i);
然后,接下来是普通的言和 tarjan
[code]int dfs_clock,dfn[MAXN]; int scc_cnt,scc_num[MAXN]; int low[MAXN]; stack <int> s; void dfs(int u) { low[u] = dfn[u] = ++dfs_clock; s.push(u); for(int i = first[u];i != -1;i = next[i]) { int v = l[i].t; if(!dfn[v]) { dfs(v); low[u] = min(low[u],low[v]); } else if(!scc_num[v]) { low[u] = min(low[u],dfn[v]); } } if(low[u] == dfn[u]) { scc_cnt ++; while(true) { int x = s.top(); s.pop(); scc_num[x] = scc_cnt; if(x == u) break; } } return; }
最后,跑个spfa什么的就好了
是最长路,最长路哦~~
[code]int use[MAXN],dis[MAXN]; deque <int> q; void spfa(int S) { memset(use,0,sizeof(use)); memset(dis,0x80,sizeof(dis)); dis[S] = val[S]; use[S] = true; q.push_back(S); q.push_back(80001); while(!q.empty()) { int u = q.front(); q.pop_front(); use[u] = false; for(int i = first[u];i != -1;i = next[i]) { int v = l[i].t; if(dis[v] < dis[u] + l[i].v + val[v]) { dis[v] = dis[u] + l[i].v + val[v]; if(use[v]) continue; if(dis[v] > dis[q.front()]) q.push_front(v); else q.push_back(v); use[v] = true; } } } return; }
顺带一提,ans要这样处理
[code] int ans = 0; for(int i = 1;i <= n;i ++) ans = max(ans,dis[i]);
总而言之,嘛
就是这样了
[code]#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <queue> #include <stack> using namespace std; const int MAXN = 80000 + 5; const int MAXM = 200000 + 5; struct edge { int f,t,v; double c; }l[MAXM << 1]; int first[MAXN],next[MAXN << 1],tot; void init() { memset(first,0xfff,sizeof(first)); tot = 0; return; } void build(int f,int t,int v,double c) { l[++tot] = (edge){f,t,v,c}; next[tot] = first[f]; first[f] = tot; return; } int dfs_clock,dfn[MAXN]; int scc_cnt,scc_num[MAXN]; int low[MAXN]; stack <int> s; void dfs(int u) { low[u] = dfn[u] = ++dfs_clock; s.push(u); for(int i = first[u];i != -1;i = next[i]) { int v = l[i].t; if(!dfn[v]) { dfs(v); low[u] = min(low[u],low[v]); } else if(!scc_num[v]) { low[u] = min(low[u],dfn[v]); } } if(low[u] == dfn[u]) { scc_cnt ++; while(true) { int x = s.top(); s.pop(); scc_num[x] = scc_cnt; if(x == u) break; } } return; } int val[MAXN]; int get_val(int i) { int ret = l[i].v; int nowval = l[i].v; while(1) { nowval = nowval * l[i].c; if(!nowval) return ret; ret += nowval; } } int use[MAXN],dis[MAXN]; deque <int> q; void spfa(int S) { memset(use,0,sizeof(use)); memset(dis,0x80,sizeof(dis)); dis[S] = val[S]; use[S] = true; q.push_back(S); q.push_back(80001); while(!q.empty()) { int u = q.front(); q.pop_front(); use[u] = false; for(int i = first[u];i != -1;i = next[i]) { int v = l[i].t; if(dis[v] < dis[u] + l[i].v + val[v]) { dis[v] = dis[u] + l[i].v + val[v]; if(use[v]) continue; if(dis[v] > dis[q.front()]) q.push_front(v); else q.push_back(v); use[v] = true; } } } return; } int n,m,S; int ff[MAXM],tt[MAXM],vv[MAXM]; double cc[MAXM]; void solve() { scanf("%d",&S); dfs(S); for(int u = 1;u <= n;u ++) for(int i = first[u];~i;i = next[i]) if(scc_num[u] == scc_num[l[i].t]) val[scc_num[u]] += get_val(i); init(); for(int i = 1;i <= m;i ++) if(scc_num[ff[i]] != scc_num[tt[i]]) build(scc_num[ff[i]],scc_num[tt[i]],vv[i],cc[i]); spfa(scc_num[S]); int ans = 0; for(int i = 1;i <= n;i ++) ans = max(ans,dis[i]); printf("%d\n",ans); return; } int main() { init(); scanf("%d %d",&n,&m); for(int i = 1;i <= m;i ++) { scanf("%d %d %d %lf",&ff[i],&tt[i],&vv[i],&cc[i]); build(ff[i],tt[i],vv[i],cc[i]); } solve(); return 0; }
相关文章推荐
- 揭秘全美第一黑客组织Anonymous(匿名者)的装备库
- Eclipse使用技巧及个性化设计
- Dyslexic Gollum
- Coherence企业级缓存
- 蓝懿ios 技术内容和心得 10.25
- 编译原理:第八节
- css个人随笔,适合新手总结整理
- AVRWARE++开发笔记7:74HC595串行控制LED灯实验
- KVC&KVO
- BadUSB的前世今生:USB RUBBER DUCKY和Teensy USB
- [洛谷1163]银行贷款
- Executor 和Executors
- Android 使用OkHttp扩展Volley
- 前端面试问题集
- 打造你的专属黑客U盘
- c++ primer第五版(中文)习题答案 第二章第一节-基本内置类型
- 老鸟谈谈JAVA EE的学习
- loadrunner性能测试步骤
- Dozer 自定义Converter -- LocalDateTime to Date
- J2EE通过tomcat部署的两种方式