POJ2947解题报告
原题链接:POJ2947
思路:本题是用高斯消元以及同余方程做,但是需要注意整数高斯消元避免使用除法。还需注意同余方程的解的问题、方程式与未知数个数不等问题。
错误报告:这题总时间花了应该有七八个小时了。第一次做忽略了方程式个数不等于未知数个数时情况,并且对于何时无解、何时多解判断方法错误,在消元方面我使用了最小公倍数(异曲同工哈?)避免消元后出现的小数。今天又用了近四小时更改,发现如下错误:
- 当某个未知数无系数时,说明该未知数是自由元;
- 虽然我们是在求同余方程组的高斯消元,但在运算过程中如果对其+7再取模可能会造成结果不同;
- 当无解时,后k个方程(消元消掉了)未知数系数全部为零,故只需判断其常数项是否为0;
- 当有解时,由于同余方程的缘故,依次将已求出的未知数带入方程,(由于最后得出来的系数矩阵是个三角矩阵)。
代码示例:
#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<map>
using namespace std;
map<string,int> data;
const int MAXN = 350;
int a[MAXN][MAXN];
int b[MAXN],ans[MAXN];
int n,m,x,num;
string s,e;
void init(){
data["MON"] = 1; data["TUE"] = 2;
data["WED"] = 3; data["THU"] = 4;
data["FRI"] = 5; data["SAT"] = 6;
data["SUM"] = 7;
}
void solve(){
int i = 1,j = 1,l,x,y;
while(i <= m && j <= n){
for(l = i;l <= m;l++){
if(a[l][j]) break;
}
if(l > m){ //attention!
j++;
continue;
}
for(int k = n;k;k--) swap(a[l][k],a[i][k]);
swap(b[l],b[i]);
x = a[i][j];
for(l = i+1;l <= m;l++){
y = a[l][j];
for(int k = j;k <= n;k++){
a[l][k] = (a[l][k]*x - a[i][k]*y)%7;//attention!
}
b[l] = (b[l]*x - b[i]*y)%7;//too!
}
i++,j++;
}
for(l = i;l <= m;l++) //attention!
if(b[l]){ puts("Inconsistent data."); return; }
if(i != j || j < n){ puts("Multiple solutions."); return;}
//分别对应变量系数为0、方程数不够未知数个数
int k;
//for(i = 1;i <= n;i++) cout << b[i] << " " << a[i][i] << endl;
for(i--,j--;i;i--,j--)
{
for(l=0,k=j+1;k<=n;k++) l+=a[i][k]*ans[k];
for(k=3;k<=9;k++)
if((a[i][j]*k%7+7)%7==((b[i]-l)%7+7)%7) ans[i]=k;
}
for(i = 1;i < n;i ++) printf("%d ",ans[i]);
cout << ans[i] << endl;
}
int main(){
init();
while(scanf("%d%d",&n,&m) && n && m){
memset(a,0,sizeof a);
memset(b,0,sizeof b);
memset(ans,0,sizeof ans);
for(int i = 1;i <= m;i++){
scanf("%d",&num);
cin >> s >> e;
b[i] = (data[e] - data[s] + 8) % 7;
while(num--){
scanf("%d",&x);
a[i][x]++;
}
for(int j = 1;j <= n;j++) a[i][j] %= 7;
}
solve();
}
}