序
作为一只菜鸡,本场比赛的题一下子把我搞懵逼了,在队友过了H之后,剩余的时间无所事事,于是就开始各种瞎搞F题,最后还真的用一种制杖操作给过了,在此放出这种方法,主要是因为我也不知道为什么能过,希望和各位大佬一起探讨一下,如果有大佬能给出样例就更好了,欢迎大家指正,求各位轻虐,鄙人在此谢过了233.
主体思路
这种方法制杖的地方就在于,我是贪心写的orz(可把我牛逼坏了,叉会儿腰,等等......腰呢!?)。我最初的想法是,可以看成一开始就有2*n个人在一组,竞争值是0,这时你要依次取出n个人来,使最终的竞争值最大,然后我就想到了每一步贪心的方法......(是不是很奇葩?)
最初的想法是这样的,在一开始先将矩阵的每一行的和求出来,这个值的含义是:第i行的和表示你取走第i个人之后增加的竞争值,每次选取最大的那个人,每当取走一个人,就把他所在的行和列删除,然后重复以上过程,n次后就可以得到一个值,但这个答案显然是错误的。
因为每次取下一个人的时候,都会影响之前所得到的竞争值,举个例子说,若是先取走了1号,当前竞争值是
,假如接下来取走2号,那么原先的竞争值就会损失一部分,即
,然后还会得到
,所有从第2步开始,一直到第n步,需要考虑当前行的和减去已选取的人的影响/的最大值,但是考虑了这一点之后依然没有过,赛后看结果只过了36%。
除此之外,还有一个是贪心的起始点的问题,因为当选取第一个人的时候,另一边没有影响,在缺乏这一约束的情况下,起始点的选取应该如何抉择?所以我干脆试了
次,然而依然没有过,赛后看结果,这份代码过了68%。
至此,在赛中我已经放弃了这个方法,后来是学姐帮忙搜过的。(事实上学姐一开始就说搜索,还有枚举也可以,没想到赛后看代码真的有大佬400行枚举)
赛后我又重新构思,发现好像这个方法只是不断贴近正确结果,例如第一步的选取,我依次尝试,就可以一定程度提高正确率,那么我第二步的选取也遍历一遍呢?按照这个数据量应该是可以把前四步的选取情况都暴力出来的,那么应该差不多过了。
然后,我只考虑了前两步,后面直接贪,就过了......过了......了......
代码
//加了注释就成了14ms,我也不知道为什么
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll a[30][30];//存竞争值的数组
bool bo[30];//好像是定义了没用上的东西
ll jl[30];//同上
struct node{
ll z;//当前状态下对剩余人的竞争值之和
ll f;//标记序号
ll si;//已选取的人的影响值
ll bj;//标记贡献值,bj=z-si
}b[30];//存每个人的信息
bool cmp(node x,node y){
return x.bj<y.bj;
}
int main(){
ll n;
node t1;
scanf("%lld",&n);
for(ll i=1;i<=n*2;i++){
for(ll j=1;j<=n*2;j++){
scanf("%lld",&a[i][j]);
}
}
ll ans=0,ans1=0;
for(int k=1;k<=n*2;k++)//初始点选取
{
for(int q=1;q<=n*2;q++){//第二个点
ans=0;
//每次重新初始化b,制杖操作,不要理会
for(int hh=1;hh<=n*2;hh++){
b[hh].z=0;
}
for(ll i=1;i<=n*2;i++){
for(ll j=1;j<=n*2;j++){
b[i].z+=a[i][j];
b[i].f=i;
b[i].si=0;
}
}
if(k==q)
continue;
//把要选取的两个点放最后
t1=b[k];
b[k]=b[n*2];
b[n*2]=t1;
t1=b[q];
b[q]=b[n*2-1];
b[n*2-1]=t1;
//第一步的处理
ans+=b[n*2].z-b[n*2].si;
for(ll j=1;j<=n*2-1;j++){
b[j].z-=a[b[j].f][b[n*2].f];
b[j].si+=a[b[j].f][b[n*2].f];
b[j].bj=b[j].z-b[j].si;
}
//剩下每一步的处理,每次对贡献值排序
for(ll i=2;i<=n;i++){
ans+=b[n*2+1-i].z-b[n*2+1-i].si;
for(ll j=1;j<=n*2-i;j++){
b[j].z-=a[b[j].f][b[n*2+1-i].f];
b[j].si+=a[b[j].f][b[n*2+1-i].f];
b[j].bj=b[j].z-b[j].si;
}
sort(b+1,b+n*2+1-i,cmp);
}
//更新答案最大值
ans1=max(ans1,ans);
}
}
printf("%lld\n",ans1);
}
/*3
0 3 5 4 1 2
3 0 7 8 9 1
5 7 0 11 2 3
4 8 11 0 5 6
1 9 2 5 0 7
2 1 3 6 7 0*/

京公网安备 11010502036488号