又到了一年一度的明明生日了,明明想要买BBB样东西,巧的是,这BBB样东西价格都是AAA元。
但是,商店老板说最近有促销活动,也就是:
如果你买了第III样东西,再买第JJJ样,那么就可以只花KI,JK_{I,J}KI,J元,更巧的是,KI,JK_{I,J}KI,J竟然等于KJ,IK_{J,I}KJ,I。
现在明明想知道,他最少要花多少钱。
第一行两个整数,A,BA,BA,B。
接下来BBB行,每行BBB个数,第III行第JJJ个为KI,JK_{I,J}KI,J。
我们保证KI,J=KJ,IK_{I,J}=K_{J,I}KI,J=KJ,I并且KI,I=0K_{I,I}=0KI,I=0。
特别的,如果KI,J=0K_{I,J}=0KI,J=0,那么表示这两样东西之间不会导致优惠。
一个整数,为最小要花的钱数。
1 1
0
1
3 3
0 2 4
2 0 2
4 2 0
7
样例解释222
先买第222样东西,花费333元,接下来因为优惠,买1,31,31,3样都只要222元,共777元。
(同时满足多个“优惠”的时候,聪明的明明当然不会选择用444元买剩下那件,而选择用222元。)
数据规模
对于30%30%30%的数据,1≤B≤101 \le B \le 101≤B≤10。
对于100%100%100%的数据,1≤B≤500,0≤A,KI,J≤10001 \le B \le 500,0 \le A,K_{I,J} \le 10001≤B≤500,0≤A,KI,J≤1000。
最小生成树prim + 优先队列版的堆优化
这道题目的意思是有B个商品,每个商品的价格是A,但是商品会打折,就是你买了B中某个商品后,再买其他的商品可能会得到一个优惠,要注意的是,第一次买的商品保证没有优惠,然后其他的商品为0代表没优惠,有“优惠”时还可能比原价还贵(黑心商家 ),要注意判断。
最初没注意到最小生成树只会把后n-1条边的值加上,一直漏了第一个买的值(第一个值没有优惠,所以应该就是A的值),所以初始值看作A,然后加一遍prim 的路径上的值就可以了
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
struct node{
int v,w;
node(int a,int b){v=a;w=b;} //构造结构体
friend bool operator<(node a,node b){ //重载
return a.w>b.w;
}
};
const int maxn=550;
const int inf=1<<27; //代表两点无法到达
int A,B,ans=0; //每样价格A,总的B件物品,ans为答案
int x,dis[maxn]; //dis记录各点到已形成树(把已形成的看作整体)的最小路径
vector<node> g[maxn]; //邻接表存边
bool vis[maxn]={false}; //判断是否走过
priority_queue<node> q; //优先队列用来模拟堆优化
int prim()
{
fill(dis,dis+maxn,inf);
dis[1]=A; //注意,这里第一个初始设为A,因为没有优惠
q.push(node(1,0)); //入队
while(!q.empty())
{
int u=q.top().v;
q.pop();
if(vis[u]) continue;
ans += dis[u]; //加上该边
vis[u]=1; //记录走过
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i].v; //取出下一个点
int w=g[u][i].w; //取出这条边的长度(折扣价格)
if(vis[v]==false) //没访问过才去访问
{
if(dis[v] > w) //优化距离
dis[v]=w;
q.push(node(v,dis[v])); //入队
}
}
}
return ans;
}
int main()
{
cin>>A>>B;
for(int i=1;i<=B;i++)
{
for(int j=1;j<=B;j++)
{
cin>>x; //买了i后j的价格
if(x==0) x=A; //等于0代表没有优惠
else x=min(x,A); //可能给的优惠价格比原价格还贵
g[i].push_back(node(j,x)); //双向边
g[j].push_back(node(i,x));
}
}
cout<<prim(); //输出结果
return 0;
}