第一题没有什么说的,题目我都没看懂,并没有理解他的包围,赛后大佬的代码我也看了,嗯,没看懂。。。
第二题是数据水了,正解为全局最小割,我并没这样做出来,我只是单纯的用并查集删了点(可用单链卡掉),竟然过了。。(据说数据水到不用并查集也可以过)
度度熊的王国战略
Accepts: 674
Submissions: 6056
Time Limit: 40000/20000 MS (Java/Others)
Memory Limit: 32768/132768 K (Java/Others)
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#define inf 0x3f3f3f3f
using namespace std;
long long num[100010];
int n,m;
int pre[3001];
void init(){
for(int i=1;i<3001;i++)
pre[i]=i;
}
int Find(int x){
if(x!=pre[x])
return pre[x]=Find(pre[x]);
return x;
}
void mix(int x,int y){
int xx=Find(x),yy=Find(y);
if(xx!=yy){
pre[xx]=yy;
}
}
int main(){
int a,b,c;
while(~scanf("%d %d",&n,&m)){
bool flag=false;
memset(num,0,sizeof(num));
init();
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
if(a!=b){
num[a]+=c;
num[b]+=c;
mix(a,b);
}
}
int cnt=0;
for(int i=1;i<=n;i++){
if (pre[i]==i)
cnt++;
}
if(cnt==1)
flag=true;
if(flag){
long long ans=inf;
for(int i=1;i<=n;i++){
if(ans>num[i])
ans=num[i];
}
printf("%I64d\n",ans);
}
else {
printf("0\n");
}
}
return 0;
}
正解:
#include<bits/stdc++.h>
#define N 3005
#define mk make_pair
using namespace std;
int a[N][N],T[N][N],F[N],vis[N];
int dead[N],pos[N],u,v,w,i,j,n,m,ans;
struct Heap{
int id[N],len;
void up(int x){
for (;x>1;x>>=1)
if (F[id[x]]>F[id[x>>1]])
swap(pos[id[x]],pos[id[x>>1]]),swap(id[x],id[x>>1]);
else return;
}
void pop(){
pos[id[len]]=0;if ((--len)==0) return;
id[1]=id[len+1];pos[id[1]]=1;
for (int x=1;(x<<1)<=len;){
int y=((x<<1)==n||F[id[x<<1]]>F[id[x<<1|1]])?(x<<1):(x<<1|1);
if (F[id[x]]>=F[id[y]]) return;
swap(pos[id[x]],pos[id[y]]);swap(id[x],id[y]);x=y;
}
}
void add(int x){
if (!pos[x]) id[pos[x]=++len]=x,up(len);
else up(pos[x]);
}
void clear(){len=0;}
}G;
void work(){
for (int i=1;i<=n;i++)
F[i]=-1e9,vis[i]=pos[i]=0;
int S,p,q;
for (int i=1;i<=n;i++)
if (!dead[i]) {S=i;break;}
G.clear();F[S]=0;
G.len=1;pos[G.id[1]=S]=G.id[1];
while (G.len){
int x=G.id[1];vis[x]=1;G.pop();
for (i=1;i<=*a[x];i++){
int y=a[x][i];
if (vis[y]) continue;
F[y]+=T[x][y];G.add(y);
}
p=q;q=x;
}int sum=0;
for (int i=1;i<=*a[q];i++)
sum+=T[q][a[q][i]];
//printf("%d\n",sum);
ans=min(ans,sum);
for (int i=1;i<=n;i++)
if (!dead[i]&&i!=q&&i!=p)
if (T[q][i]&&!T[p][i]) a[p][++*a[p]]=i;
for (int i=1;i<=n;i++)
if (!dead[i]&&i!=p&&i!=q)
T[i][p]+=T[i][q],T[p][i]+=T[q][i];
dead[q]=1;
//printf("%d %d\n",p,q);
int debug=(p==4&&q==3);
for (int i=1;i<=n;i++)
if (!dead[i]&&i!=q){
int j=1;
for (;j<=*a[i];j++)
if (a[i][j]==q) break;
if (j<=*a[i]){
for (;j<*a[i];j++)
a[i][j]=a[i][j+1];
--(*a[i]);
}
if (!T[i][p]) continue;
for (j=1;j<=*a[i];j++)
if (a[i][j]==p) break;
if (j>(*a[i])) a[i][++*a[i]]=p;
}
//printf("Delete:%d Sum:%d\n",q,sum);
//for (int i=1;i<=n;i++)
//if (!dead[i]) for (int j=1;j<=*a[i];j++)
//printf("%d->%d %d\n",i,a[i][j],T[i][a[i][j]]);
}
int main(){
while (scanf("%d%d",&n,&m)!=EOF){
if (!n) return 0;
memset(T,0,sizeof(T));
for (i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
if (u==v) continue;
T[u][v]+=w;T[v][u]+=w;
}
//printf("%d\n",T[1][1]);
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (T[i][j]) a[i][++*a[i]]=j;
/*for (int i=1;i<=n;i++)
for (int j=1;j<=*a[i];j++)
printf("%d->%d %d\n",i,a[i][j],T[i][a[i][j]]);*/
ans=2e9;
for (int tmp=min(n-1,1000);tmp;tmp--)
work();
printf("%d\n",ans);
for (i=1;i<=n;i++) *a[i]=dead[i]=0;
}
}
第三个题是签到题,我们先判断是否能够打败所有怪兽,然后就是一个裸背包。
度度熊与邪恶大魔王
Accepts: 3666
Submissions: 22474
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
#include <cstdio>
#include <cstring>
#include <iostream>
#define inf 0x3f3f3f3f
#define LL long long
using namespace std;
int n,m,a[100010],b[100010];
int k[10010],p[10010];
long long dp[12][1005<<1];
int main(){
while(~scanf("%d%d",&n,&m)){
int mx0=0,mx1=0;
for(int i=1;i<=n;i++){
scanf("%d%d",&a[i],&b[i]);
mx0=max(mx0,b[i]);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&k[i],&p[i]);
mx1=max(mx1,p[i]);
}
if(mx0>=mx1){
printf("-1\n");
continue;
}
memset(dp,inf,sizeof(dp));
for(int x=0;x<=10;x++){
dp[x][0]=0;
for(int i=1;i<=m;i++){
if(p[i]<=x)
continue;
for(int j=p[i]-x;j<=2000;j++){
dp[x][j]=min(dp[x][j],dp[x][j-(p[i]-x)]+k[i]);
}
}
for(int i=2000;i>0;i--){
dp[x][i]=min(dp[x][i],dp[x][i+1]);
}
}
LL ans=0;
for(int i=1;i<=n;i++){
ans+=dp[b[i]][a[i]];
}
printf("%I64d\n",ans);
}
return 0;
}
第四个题是一个比较有难度的dp,这个题多亏了qls和csy在ACfun里的提示,题意没有很清楚,这其实就是一个01背包,但是要求优先最大化总得分,然后最小化序列之和,最后最大化花费,要求输出字典序最小的解,在不打饭的情况下不输出空行(我PE了4发...)。
度度熊的午饭时光
Accepts: 823
Submissions: 9241
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
这个题开始用背包的思路去想的
pre[i][j].first代表的是你取的最后一个物品编号,因为dp就是物品编号小到大的顺序dp的,所以这个一定是当前最小
dp[i][j].second代表的是当前序列之和,如果最大值相同,取序号和最小
dp[i][j].first代表的是遍历到第i个物品总费用为j的情况下的最大价值
然后看代码应该就懂了
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
struct node{
int score,cost;
}xin[10001];
pair<int,int>dp[102][1001],pre[102][1001];
int p[10000];
int main(){
int Case=0,t;
int b,n;
scanf("%d",&t);
while(t--){
Case++;
scanf("%d%d",&b,&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&xin[i].score,&xin[i].cost);
}
for(int i=0;i<=n;i++){
for(int j=0;j<=b;j++){
dp[i][j].first=dp[i][j].second=-1;
pre[i][j].first=pre[i][j].second=-1;
}
}
dp[0][0].first=dp[0][0].second=0;
int ans1=0,ans2=0,x,y;
for(int i=1;i<=n;i++){
for(int j=xin[i].cost;j<=b;j++){
for(int k=0;k<i;k++){
if(dp[k][j-xin[i].cost].first==-1)
continue;
if(dp[i][j].first<dp[k][j-xin[i].cost].first+xin[i].score){
dp[i][j].first=dp[k][j-xin[i].cost].first+xin[i].score;
dp[i][j].second=dp[k][j-xin[i].cost].second+i;
pre[i][j].first=k;
pre[i][j].second=j-xin[i].cost;
}
else if(dp[i][j].first==dp[k][j-xin[i].cost].first+xin[i].score){
if(dp[i][j].second>dp[k][j-xin[i].cost].second+i){
dp[i][j].second=dp[k][j-xin[i].cost].second+i;
pre[i][j].first=k;
pre[i][j].second=j-xin[i].cost;
}
}
}
if(dp[i][j].first>ans1){
ans1=dp[i][j].first;
ans2=dp[i][j].second;
x=i,y=j;
}
else if(dp[i][j].first==ans1){
if(ans2>dp[i][j].second){
ans2=dp[i][j].second;
x=i,y=j;
}
}
}
}
printf("Case #%d:\n",Case);
printf("%d %d\n",ans1,y);
int cnt=0;
while(x!=0&&x!=-1){
p[cnt++]=x;
int k1=x,k2=y;
x=pre[k1][k2].first;
y=pre[k1][k2].second;
}
for(int i=cnt-1;i>=0;i--){
printf(i!=0?"%d ":"%d\n",p[i]);
}
}
return 0;
}
对于第五题来说,是一个卡特兰数,金桔告诉我的,我并没有看出来,卡特兰数我练的也不熟,想了一个多小时没有思路就放弃了,赛后看了大牛们的代码,卡特兰数+扩展欧几里得,我还是慢慢研究这个题吧。
以上全部题目来自:http://bestcoder.hdu.edu.cn/contests/contest_show.php?cid=774