题解 P1854 【花店橱窗布置】
欢迎访问博客,获得更佳阅读体验 戳这里
题面
洛谷 P1854
题目描述
某花店现有
每个花瓶的形状和颜色也不相同,因此,当各个花瓶中放入不同的花束时,会产生不同的美学效果,并以美学值(一个整数)来表示,空置花瓶的美学值为
| 花名/花瓶编号 | 花瓶1 | 花瓶2 | 花瓶3 | 花瓶4 | 花瓶5 |
|---|---|---|---|---|---|
| 杜鹃花 | 7 | 23 | -5 | -24 | 16 |
| 秋海棠 | 5 | 21 | -4 | 10 | 23 |
| 康乃馨 | -21 | 5 | -4 | -20 | 20 |
根据表格,杜鹃花放在花瓶
为了取得最佳的美学效果,必须在保持花束顺序的前提下,使花的摆放取得最大的美学值,如果具有最大美学值的摆放方式不止一种,则输出任何一种方案即可。
输入格式
输入文件的第一行是两个整数
输出格式
输出文件的第一行是一个整数,为最大的美学值;接下来有
输入样例
3 5
7 23 -5 -24 16
5 21 -4 10 23
-21 5 -4 -20 20
输出样例
53
2 4 5
说明
感谢@罗恺 提供SPJ
思路
读完题,你一定已经懵逼了。
没错,这种大赛的题目总是有着像 语文/English 阅读理解的题面。
下面我来划一下重点:
给定一个
F \times J 的矩阵A(F \leq J) ,求一个序列a_1,a_2,…,a_n 满足使得 $A[1][a_1]+A[2][a_2]+…+A[n][a_n] $最大。 矩阵中 $A_{ij}$ 可能含有负数。
很显然这是一道DP,然而,一样能把它看成是一道图论题。
把矩阵看成一张图的话,就是求从第
具体的做法,我们考虑设一个虚点
然后从
最后比较一下第
需要注意的是题目要求的路径是正序的,所以需要借助一个栈把路径正过来。
这种算法没有DP跑得快,但思路很显然很暴力。(毕竟不是标算嘛...)
Code
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define trans(i, j) ((i - 1) * V + j)
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXF = 105;
const int MAXV = 105;
const int MAXN = MAXF * MAXV;
int cnt = 0, F, V, ma[MAXF][MAXV];
int head[MAXN], dis[MAXN + 1], pre[MAXN];
bool vis[MAXN + 1];
struct Edge
{
int u, v, w, next;
} e[800000];
inline void add_Edge(int u, int v, int w)
{
e[++cnt].u = u, e[cnt].v = v, e[cnt].w = w;
e[cnt].next = head[u], head[u] = cnt;
}
void SPFA(int s)
{
queue<int> q;
for (int i = 1; i <= F * V; i++)
dis[i] = -INF;
dis[s] = 0;
q.push(s);
vis[s] = 1;
while (!q.empty())
{
int u = q.front();
q.pop();
vis[u] = 0;
for (int i = head[u]; i; i = e[i].next)
{
int v = e[i].v, w = e[i].w;
if (dis[u] + w > dis[v])
{
dis[v] = dis[u] + w;
pre[v] = u;
if (!vis[v])
{
q.push(v);
vis[v] = 1;
}
}
}
}
}
int main()
{
scanf("%d %d", &F, &V);
for (int i = 1; i <= F; i++)
for (int j = 1; j <= V; j++)
scanf("%d", &ma[i][j]);
for (int j = 1; j <= V; j++)
add_Edge(0, trans(1, j), ma[1][j]);
for (int i = 1; i < F; i++)
for (int j = 1; j < V; j++)
for (int k = j + 1; k <= V; k++)
add_Edge(trans(i, j), trans(i + 1, k), ma[i + 1][k]);
SPFA(0);
int ans = -INF, end;
for (int j = 1; j <= V; j++)
{
int u = trans(F, j);
if (ans < dis[u])
ans = dis[u], end = u;
}
printf("%d\n", ans);
int sta[105];
for (int i = F, j = end; i && j; j = pre[j], i--)
sta[i] = j - (i - 1) * V;
for (int i = 1; i <= F; i++)
printf("%d ", sta[i]);
return 0;
}