1. 程式人生 > >Wannafly挑戰賽26-B 冥土追魂

Wannafly挑戰賽26-B 冥土追魂

思路:對於行列選取,是選擇所有行中的最大值的最小值,當是並不能用貪心來做,例如

2 2 2
7 8
1 9

如果用貪心的話就是7+8=15,但是最小值是1+9=10

對於a[i][j]行按照由大到小排序,列按照行總和由小到大排序,選取順序應該是以每次選擇一整行來考慮的,即若k>=m,則選取前m個數一定是選取一整行的數的,可以這樣考慮借鑑部落格Wannafly挑戰賽26: B. 冥土追魂(思維題)

假設第1行選擇了前x個數字, 第2行選擇了前y個數字,且x, y<m(都沒選滿一行)

首先肯定a[2][y+1]>a[1][x] (如果a[2][y+1]<=a[1][x]的話,那麼選擇a[2][y+1]更優,而不會選a[1][x]了)   那麼可以得出a[2][y+1]>a[1][x] → a[2][y]>a[1][x] → a[2][y]>a[1][x+1],這樣的話如果第二行選擇前y-1個數字,第一行選擇前x+1個一定更優

t1=k/m,t2=k%m, 那麼可以對於t2可以列舉所有行,在取前t1(不包含t2選取行)行,儲存最小值即可

Code :

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;

const int MAX_N=1005;
const int MAX_M=1005;
int n,m,s;
int a[MAX_N][MAX_M];
struct node{
	LL Sum[MAX_M];
	int id;
	bool operator<(const node &p)const{
		return Sum[m]<p.Sum[m];
	}
}d[MAX_N];

bool cmp(const int &a,const int &b){
	return a>b;
}
int main()
{
	ios::sync_with_stdio(false);
	while(cin>>n>>m>>s){
		for(int i=1;i<=n;++i)
			for(int j=1;j<=m;++j)
				cin>>a[i][j];
		for(int i=1;i<=n;++i)
			sort(a[i]+1,a[i]+m+1,cmp);
		for(int i=1;i<=n;d[i].id=i++)
			for(int j=1;j<=m;++j)
				d[i].Sum[j]=d[i].Sum[j-1]+a[i][j];
		sort(d+1,d+n+1);
		LL ans=1e18,num;
		for(int i=1;i<=n;++i)
		{
			num=d[i].Sum[s%m];
			for(int j=1,t=s/m;j<=n&&t>0;++j)
			{
				if(i==j&&s%m)	continue;
				num+=d[j].Sum[m];
				--t;
			}
			ans=min(ans,num);
		}
		cout<<ans<<endl;
	}
	
	return 0;
}