拯救亚特兰蒂斯(savior.pas)
Bug魔王派出了N种怪物来入侵亚特兰蒂斯,聪明的亚特兰蒂斯国王Cubic预先得知了Bug魔王的阴谋,并了解到每种怪物都对应一种剑术和一种法术,这种怪物可以被对应的剑术打败也可以被对应的法术打败。不同的怪物可能对应不同的剑术和法术,而一种剑术或法术可以击败多种怪物。只要Cubic得到某怪物的信息,他就可以知道对应的剑术和法术,不会只知其一。
令国王感到欣慰的是亚特兰蒂斯最优秀的剑术师Xixi和最优秀的法术师Haha决定挺身而出,保卫国家。但问题是他们并不会这些特定的剑术和法术,必须抓紧时间学习。由于学习新剑术或新法术需要闭关,为防止Bug魔王偷袭,必须留下一个负责看守,因此两人不能同时学习。学习一种剑术或一种法术的时间都是1。现在的问题是他们到底需要学习那些剑术和法术,才能在最短的时间内拥有打败所有怪物的能力呢?
聪明的Cubic国王也发愁了,于是他决定聘请更聪明的你为亚特兰蒂斯的顶级技术顾问(相当于副科级),来帮他解决这个问题,全靠你了。
输入格式:输入有多组数据。对于每组数据:
第1行是3个整数P(1<=P<=10000),N(0<=N<=500)和M(0<=M<=500),分别表示怪物、剑术和法术的种数。接下来P行,每行一个字符串,分别表示P种怪物的名字。
再接下来N+M行,表示一种剑术或法术的信息。前N行是剑术,后M行是法术。对于每一行,首先是一个字符串,表示剑术或法术的名字;然后是一个非负整数K(K<=P),表示这种剑术或法术可以击败的怪物种数;然后就是K个字符串,表示K种怪物的名字。这些怪物都在上面的P种怪物之内。
所有的字符串都只由字母和连字符(-)组成,长度不超过15。两个字符串以空格隔开。所有字符串都不相同。
最后1行有3个-1,表示输入结束。
输出格式:对于每组数据,输出一个整数,表示要拥有打败所有怪物的能力所需要的最少时间。如果无法打败所有的怪物,输出“Poor Atlantis!”。
Savior.in |
Savior.out |
5 3 2 ant rocking kinfkong savior magicpig AlongNineSword 2 ant kinfkong HuaShanSword 2 rocking savior TaijiSword 1 magicpig Wind_walk 3 ant rocking magicpig Blade-storm 2 kinfkong savior -1 -1 -1
|
2 |
这道题是个二分图求最大匹配,刚看到的时候在想我是不是应该把monster和sword&&magic连起来(当时内心:他这不是存心搞我,为什么要搞个sword又搞个magic),后来才听说是把sword和magic连起来,monster作为边,利用二分图最大匹配等于最小点覆盖来做。
我的想法还是太朴素,构建出g[i][j]数组即剑术i和法术j能杀同一种怪物,为了求这个我先建了两个数组每种剑术能杀的怪物,每种法术能杀的怪物,最后再导出g数组,时间复杂度疯狂上升,附上终极原始之丢人代码,开始拿了个60分到80分(这cena是真实不稳)
#include<stdio.h>
#include<stdlib.h>
FILE*fin,*fout;
int p,n,m;
char sword[501][15]={0},magic[501][15]={0},monster[10001][15]={0};
char s1[1000]={0},s2;
int num1[10005]={0},num2[10005]={0},dk[505][10000]={0},dk2[505][10000]={0},g[505][505]={0},y1[10005]={0},link[10005]={0};
int find(int v)
{
int i,flag=0;
for(i=1;i<=n;i++)
if(g[v][i]&&y1[i]==0)
{
y1[i]=1;
if(link[i]==0||find(link[i]))
{
link[i]=v;
flag=1;
return flag;}
}
return 0;
}
int main()
{
int i,j,num=0,k=0,ans=0,ans2=0;
fin=fopen("savior.in","r");
fout=fopen("savior.out","w");
while(1)
{
fscanf(fin,"%d%d%d",&p,&n,&m);
ans=0;ans2=0;
memset(num1,0,sizeof(num1));
memset(num2,0,sizeof(num2));
memset(g,0,sizeof(g));
memset(sword,0,sizeof(sword));
memset(magic,0,sizeof(magic));
memset(monster,0,sizeof(monster));
memset(s1,0,sizeof(s1));
memset(link,0,sizeof(link));
memset(dk,0,sizeof(dk));
memset(dk2,0,sizeof(dk2));
memset(y1,0,sizeof(y1));
if(p==-1&&n==-1&&m==-1)
break;
for(i=1;i<=p;i++)
fscanf(fin,"%s%c",&monster[i],&s2);
for(i=1;i<=n;i++)
{fscanf(fin,"%s%d",&sword[i],&num1[i]);
for(j=1;j<=num1[i];j++)
{fscanf(fin,"%s%c",&s1,&s2);
for(k=1;k<=p;k++)
if(!strcmp(s1,monster[k]))
{dk[i][k]=1;break;}
}
}
for(i=1;i<=m;i++)
{fscanf(fin,"%s%d",&magic[i],&num2[i]);
for(j=1;j<=num2[i];j++)
{fscanf(fin,"%s%c",&s1,&s2);
for(k=1;k<=p;k++)
if(!strcmp(s1,monster[k]))
{dk2[i][k]=1;break;}
}
}
for(i=1;i<=n;i++)
for(j=1;j<=p;j++)
{
if(dk[i][j]==1)
{
for(k=1;k<=m;k++)
if(dk2[k][j]==1)
break;
if(dk2[k][j]==1)
{g[k][i]=1;ans2++;}
}
}
for(i=1;i<=m;i++)
{
for(j=1;j<=1000;j++)
y1[j]=0;
if(find(i))
ans++;
}
if(ans2<p)
fprintf(fout,"Poor Atlantis!\n");
else
fprintf(fout,"%d\n",ans);
}
fclose(fin);
fclose(fout);
return 0;
}
隔壁dalao:我先来一手快排+二分。瞬间降低复杂度,在建立g数组这个地方时间复杂度仅略高于o(nlogn),闪电般的ac,可以说是教科书一般的操作了(好吧其实也没有那么夸张就是单纯自己没想到加菜而已)
附上闪电ac代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
FILE *fin,*fout;
struct moster{
int n,a[3];
char name[20];
};
struct moster a[10001];
struct sword1{
char name[20];
int n;
int a[501];
};
struct sword1 sword[501];
struct magic1{
char name[20];
int n;
int a[501];
};
struct magic1 magic[501];
int p,n,m,y[501],link[501],g[501][501];
char name[20];
void qsort1(int left,int right)
{
int i,j;
char mid[20];
i=left;
j=right;
strcpy(mid,a[(i+j)/2].name);
while(i<=j)
{
while(strcmp(a[i].name,mid)<0) i++;
while(strcmp(a[j].name,mid)>0) j--;
if(i<=j) {a[0]=a[i];a[i]=a[j];a[j]=a[0];i++;j--;}
}
if(i<right) qsort1(i,right);
if(j>left) qsort1(left,j);
}
int find(int i)
{
int j;
for(j=1;j<=m;j++)
if(g[i][j] && !y[j])
{
y[j]=1;
if(!link[j] || find(link[j]))
{
link[j]=i;
return 1;
}
}
return 0;
}
int main(void)
{
fin=fopen("savior.in","r");
fout=fopen("savior.out","w");
int i,j,num,k,x,x1,x2,mid,ans;
char r;
fscanf(fin,"%d%d%d",&p,&n,&m);
while(p!=-1)
{
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
g[i][j]=0;
for(i=1;i<=m;i++)
link[i]=0;
num=0;
ans=0;
for(i=1;i<=p;i++)
{
fscanf(fin,"%c%s",&r,&a[i].name);
a[i].n=0;
}
qsort1(1,p);
for(i=1;i<=n;i++)
{
fscanf(fin,"%c%s%d",&r,&sword[i].name,&k);
num=num+k;
for(j=1;j<=k;j++)
{
fscanf(fin,"%c%s",&r,&name);
x1=1;
x2=p;
while(1)
{
mid=(x1+x2)/2;
if(strcmp(a[mid].name,name)==0) {x=mid;break;}
if(strcmp(a[mid].name,name)<0) x1=mid+1;
else x2=mid-1;
}
a[x].a[1]=i;
}
}
for(i=1;i<=m;i++)
{
fscanf(fin,"%c%s%d",&r,&magic[i].name,&k);
for(j=1;j<=k;j++)
{
fscanf(fin,"%c%s",&r,&name);
x1=1;
x2=p;
while(1)
{
mid=(x1+x2)/2;
if(strcmp(a[mid].name,name)==0) {x=mid;break;}
if(strcmp(a[mid].name,name)<0) x1=mid+1;
else x2=mid-1;
}
a[x].a[2]=i;
g[a[x].a[1]][a[x].a[2]]=1;
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=m;j++)
y[j]=0;
if(find(i)) ans++;
}
if(num==p)
fprintf(fout,"%d\n",ans);
else
fprintf(fout,"Poor Atlantis!\n");
fscanf(fin,"%d%d%d",&p,&n,&m);
}
fclose(fin);
fclose(fout);
return 0;
}