题目大意: 有 n n n 个物品,称量 n + 1 n+1 n+1 次,每次选取其中若干个,但是有一次的称量得到的质量是错误的,求出最重的物品的编号。
因为 n n n 只有 100 100 100,所以愉快的考虑 O ( n 4 ) O(n^4) O(n4) 做法。
显然,直接枚举哪一次称量是错误的,然后高斯消元直接搞即可。
代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define maxn 110
int n;
double matrix[maxn][maxn];
double ans[maxn];
int shuru[maxn][maxn],w[maxn];
void gauss()//高斯消元
{
for(int i=1;i<=n;i++)
{
int p=i;
for(int j=i+1;j<=n;j++)
if(fabs(matrix[j][i])>fabs(matrix[p][i]))p=j;
if(p!=i)swap(matrix[p],matrix[i]);
for(int j=n+1;j>=i;j--)
matrix[i][j]/=matrix[i][i];
for(int j=i+1;j<=n;j++)
for(int k=n+1;k>=i;k--)
matrix[j][k]-=matrix[i][k]*matrix[j][i];
}
ans[n]=matrix[n][n+1];
for(int i=n-1;i>=1;i--)
{
ans[i]=matrix[i][n+1];
for(int j=i+1;j<=n;j++)
ans[i]-=matrix[i][j]*ans[j];
}
}
int anss=-1;
void check()
{
int v=0;//如果某一行全部为0,就是无解或无数解
for(int i=1;i<=n;i++)
{
bool tf=false;
for(int j=1;j<=n;j++)
if(fabs(matrix[i][j])>1e-10){tf=true;break;}
if(!tf){v=1;break;}
}
if(v)return;
int maxans=0;//判断是否都是正整数
for(int i=1;i<=n;i++)
if(fabs((int)ans[i]-ans[i])>1e-10||ans[i]<=0)return;
for(int i=1;i<=n;i++)
if((int)ans[i]>maxans)maxans=(int)ans[i];
int sum=0;
for(int i=1;i<=n;i++)
if((int)ans[i]==maxans)sum++,v=i;
if(sum>1)return;//判断是否只有一个最重物品
if(anss!=-1)printf("illegal"),exit(0);//判断是否有多组合法方案
anss=v;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n+1;i++)
{
scanf("%d",&shuru[i][0]);
for(int j=1;j<=shuru[i][0];j++)
scanf("%d",&shuru[i][j]);
scanf("%d",&w[i]);
}
for(int i=1;i<=n+1;i++)
{
int tot=0;
memset(matrix,0,sizeof(matrix));
for(int j=1;j<=n+1;j++)
{
if(j==i)continue;
tot++;
for(int k=1;k<=shuru[j][0];k++)
matrix[tot][shuru[j][k]]=1;
matrix[tot][n+1]=w[j];
}
gauss();
check();
}
if(anss==-1)printf("illegal");
else printf("%d",anss);
}