xdoj 1025
亮亮最近在玩一款叫做“梦想庄园”的经营游戏。在游戏中,你可以耕种,养羊甚至建造纺织厂。
如果你需要制造衣服,你首先得有布匹和毛线。布匹由棉花纺织而成;毛线由羊毛制成,而羊需要饲料才能长出羊毛,最终饲料由小麦和胡萝卜制成。
假设游戏中共有N种物品,第i种物品由其他Ci个物品制成。亮亮需要你帮他制作M个任务物品来完成销售订单。
游戏中的每个物品都有一个价格Vi,当原材料不足以制作出所有的物品时,你需要花尽量少的钱买一些物品来完成任务。你可以选择直接购买所需的任务物品,也可以购买其他物品来制作任务物品,但是每制作一次需要W的代价。
题目分析:看着好吓人啊。。其实分析清晰也很简单。每种物体既可以直接买到或者由其他物体制作得到。那么我们就取两者的最小值。制作的花费我们可以这样求得
如果x的原材料有y 那么x和y之间有一条有向边 。然后按照拓扑排序的顺序自底而上求出各个物体制作所需的价值。。很简单吗?!
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <vector> 6 using namespace std; 7 const int N=1e4+7; 8 vector < vector <int> > g(N); 9 int val[N]; 10 bool vis[N]; 11 int n,m,w; 12 void dfs (int rt) { 13 vis[rt]=1; 14 if (g[rt].size()==0) return ;// 最底层直接返回 15 int cost=w; 16 for (int i=0;i<g[rt].size();i++) { 17 int next=g[rt][i]; 18 if (!vis[next]) dfs(next); 19 cost+=val[next];//cost制作费用 20 } 21 val[rt]=min (cost,val[rt]);//取两者最小值 22 return ; 23 } 24 int main () 25 { 26 int T; 27 scanf ("%d",&T); 28 while (T--) { 29 scanf ("%d %d %d",&n,&m,&w); 30 for (int i=0;i<n;i++) g[i].clear(); 31 memset (vis,0,sizeof(vis)); 32 for (int i=0;i<n;i++) { 33 scanf ("%d",&val[i]); 34 int num; scanf ("%d",&num); 35 for (int j=0;j<num;j++) { 36 int u; scanf ("%d",&u); 37 g[i].push_back(u); 38 } 39 } 40 for (int i=0;i<n;i++) 41 if (!vis[i]) dfs (i); 42 int sum=0; 43 for (int i=0;i<m;i++) { 44 int x; scanf ("%d",&x); 45 sum+=val[x]; 46 } 47 printf ("%d\n",sum); 48 } 49 return 0; 50 }
ccf 高速公路 求联通分量 这个算法好像叫trajin 向这些科学家致敬
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <stack> 5 #include <vector> 6 using namespace std; 7 const int N=1e4+7; 8 vector < vector <int> > g(N); 9 stack <int> ss; 10 bool instack[N]; 11 bool vis[N]; 12 int dfn[N],low[N];// dfn 保存遍历序号 low 这个点所能到达的最小点 13 int ans; 14 int n,m; 15 int cnt;//访问顺序 16 void dfs (int rt) { 17 vis[rt]=1; 18 instack[rt]=1; ss.push(rt); 19 dfn[rt]=low[rt]=++cnt; 20 for (int i=0;i<g[rt].size();i++) { 21 int next=g[rt][i]; 22 if (!vis[next]) { 23 dfs (next); 24 low[rt]=min (low[rt],low[next]); 25 } 26 else if (instack[next]) { 27 low[rt]=min (low[rt],low[next]); 28 } 29 } 30 if (dfn[rt]==low[rt]) {// dfn[rt]==low[rt] 表示遍历一个联通分变量啦 31 int num=1; 32 int tmp=ss.top(); ss.pop(); instack[tmp]=0;//在栈中 说明这个点的后继子孙还没有访问完 33 while (dfn[tmp]!=low[tmp]) { num++; tmp=ss.top(); ss.pop(); instack[tmp]=0;} 34 ans+=(num-1)*num/2; 35 } 36 return ; 37 } 38 int main () 39 { 40 ios::sync_with_stdio(false); 41 cin>>n>>m; 42 for (int i=1;i<=m;i++) { 43 int x,y; cin>>x>>y; 44 g[x].push_back(y); 45 } 46 for (int i=1;i<=n;i++) 47 if (!vis[i]) dfs (i); 48 printf ("%d\n",ans); 49 return 0; 50 }
抓住青春的尾巴。。。