66pts求助
查看原帖
66pts求助
209812
Forza_Juventus楼主2022/7/27 16:15

RT,RT,思路如下,错第5,6,7点

/*luogu P1281
思路:
先不考虑如何求出第几个人看的书的编号,而是求出总时间的最小值
设f[i][j]为第i个人,总共选到第j本书的时间最短值
既然每个人至少选一本书,那么第i个人至少从第i本书选起
 j从i开始枚举,一直枚举到m
 在这之间,对于每一个j,i到j之间任何一个点都可以分割开来
 那么f[i][j] = min(max(f[i - 1][j - k]) , sum(a[j - k + 1]~a[j])) 
 
第二阶段:状态的记录
设置一个pair数组,在每次利用最小值更新某一状态后,就记录下转移前的状态
因为每个状态只进行一次循环,在循环后记录的一定是对于这个状态的最优解
所以无后效性 
*/ 

#include <bits/stdc++.h>
using namespace std;
struct node{
	pair<int , int > st = make_pair(0, 0);//当前状态 
	pair<int , int > pre_st = make_pair(0, 0);//从哪个状态转移 
}; 
int  m, tp;//m books and tot_person persons
int  book[505];
int  f[505][505];
int  sum[505];
node sta[505][505];//记录状态f[i][j]是从哪一个状态转移过来 
void __INIT()
{
	ios::sync_with_stdio(false);
	memset(f, 0x3f3f3f3f, sizeof(f));
	cin>>m>>tp;
	for(int i = 1;i <= m;++ i)
		cin>>book[i];
	for(int i = 1;i <= m;++ i)
		sum[i] = sum[i - 1] + book[i];//记录前缀和,用于算部分和(状态转移方程的后半部分) 
	return ;
}
void dfs(int x, int y)
{
	if(x == 0 || y == 0) return ;
	if(x == 1)
	{
		cout<<sta[x][y].st.first<<' '<<sta[x][y].st.second<<endl;
		return ;
	}
	else
	{
		dfs(sta[x][y].pre_st.first, sta[x][y].pre_st.second);
		cout<<sta[x][y].st.first<<' '<<sta[x][y].st.second<<endl;
		return;
	}
	return ;
}
int main()
{
	__INIT();
	for(int i = 1;i <= m;++ i)
		f[1][i] = sum[i];
	for(int i = 1;i <= m;++ i)
	{
		pair<int , int > ins = make_pair(1, i);
		sta[1][i].st = ins;
	}
	for(int i = 1;i <= m;++ i)
	{
		for(int j = i;j <= m;++ j)
		{
			int tmp;
			for(int k = j;k >= 1;-- k)
			{
				tmp = max(f[i - 1][j - k], sum[j] - sum[j - k]);
				if(f[i][j] > tmp)
				{
					f[i][j]          = tmp;
					sta[i][j].st     = make_pair(j - k + 1, j);
					sta[i][j].pre_st = make_pair(i - 1, j - k);
				} 
			}
		}
	}

//	cout<<f[tp][m]<<endl;
	dfs(tp, m);
	return 0;
} 
2022/7/27 16:15
加载中...