【Vijos-P1285】佳佳的魔法药水-Dijkstra思想

题目大意:有N种药水,以0~N-1编号,给出若干个配方,格式为A+B=C(即一个A药水和一个B药水可以合成一个C药水),可以从商店里花费一些钱来买药水,每种药水的价格不一定相同,要配出一个0号药水,求最小花费以及能满足最小花费的方案个数。

做法:我们可以用Dijkstra的思想,用已知来更新未知。我们用一个v数组来标记一种药水的最小花费是否确定,如果v[i]为真,则表示i号药水的最小花费已经确定,否则反之。同时,用cost[i]和ans[i]记录当前求出的i号药水的最小花费和满足最小花费的方案个数,f[i][j]记录一个i号药水和一个j号药水能够合成的药水编号(是不是很像邻接矩阵?),cost[i]初始化为药水在商店中的价格,ans[i]初始化为1。每次选择一个v[k]为假并且cost[k]最小的k,可以证明这个k号药水再没有其他方案使得它的最小花费更小了,然后寻找与它相关联的配方,如果k号药水可以跟另一个最小花费已经确定的j号药水合成一种药水,则更新cost[f[j][k]]和ans[f[j][k]]:如果cost[j]+cost[k]<cost[f[j][k]],则将cost[f[j][k]]更新为cost[j]+cost[k],并将ans[i]更新为1;如果cost[j]+cost[k]=cost[f[j][k]],则将ans[f[j][k]]加上ans[j]*ans[k]。更新完所有和k号药水有关的配方之后,将v[k]赋值为真,重复上述过程直到所有药水都更新过为止。最后输出cost[0]和ans[0]即可。

以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
long n;
long f[1010][1010]={0},cost[1010]={0},ans[1010]={0};

void dijkstra()
{
  long v[1010]={0},k,minimum;
  for(int i=1;i<=n;i++)
  {
    minimum=99999999;
    for(int j=0;j<n;j++)
      if (!v[j]&&cost[j]<minimum) {k=j;minimum=cost[j];}
    if (minimum==99999999) break;
    v[k]=1;
    for(int j=0;j<n;j++)
      if (v[j]&&f[j][k]>=0)
      {
        if (cost[f[j][k]]>cost[j]+cost[k]) {cost[f[j][k]]=cost[j]+cost[k];ans[f[j][k]]=ans[j]*ans[k];}
        else if (cost[f[j][k]]==cost[j]+cost[k]) ans[f[j][k]]+=ans[j]*ans[k];
      }
  }
}

void input()
{
  cin >> n;
  for(int i=0;i<n;i++)
    cin >> cost[i];
  long a,b,c;
  for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)
      f[i][j]=-1;
  while(scanf("%ld %ld %ld",&a,&b,&c)!=EOF)
  {
    f[a][b]=c;
    f[b][a]=c;
  }
  for(int i=0;i<n;i++)
    ans[i]=1;
}

void output()
{
  cout << cost[0] << " " << ans[0];
}

int main()
{
  input();
  dijkstra();
  output();
  
  return 0;
}


posted @ 2016-08-11 22:08  Maxwei_wzj  阅读(93)  评论(0编辑  收藏  举报