POJ 1166 Gauss消元 取模

2021-08-16 17:16:10 字數 3575 閱讀 5658

|——-| |——-| |——-|

| | | | | | |

|—o | |—o | | o |

| | | | | |

|——-| |——-| |——-|

​ a b c

|——-| |——-| |——-|

| | | | | |

| o | | o | | o |

| | | | | | | | |

|——-| |——-| |——-|

​ d e f

|——-| |——-| |——-|

| | | | | |

| o | | o—| | o |

| | | | | | | |

|——-| |——-| |——-|

​ g h i

(figure 1)`

move   affected clocks

1 abde

2 abc

3 bcef

4 adg

5 bdefh

6 cfi

7 degh

8 ghi

9 efhi

(figure 2)

your program is to read from standard input. nine numbers give the start positions of the dials. 0=12 o』clock, 1=3 o』clock, 2=6 o』clock, 3=9 o』clock.

your program is to write to standard output. output a shortest sorted sequence of moves (numbers), which returns all the dials to 12 o』clock. you are convinced that the answer is unique.

3 3 0

2 2 2

2 1 2

4 5 8 9
這題只有9個鐘 每個鐘可以轉0~3次 所以49

4

9列舉也可行?

但這題是乙個解方程組的思路

可以做到93

9

3的時間複雜度

先確定初末狀態

輸入給的是初始狀態

對於末狀態 我們要使得所有鐘錶歸零

我們要求解的未知數x1~x9代表9種操作所做的次數 範圍是0~3 因為做四次等於沒做

而對於係數矩陣 行號i代表第i個鐘錶會被ai

jwhi

chis

1 aij

whic

his1

的操作影響

這樣增廣矩陣的右邊列向量 代表對於每個鐘需要幾次操作(由初末狀態求得、套路)

mod4

取模操作很關鍵

如果用浮點型的高斯消元,顯然不能取模(或者說很不方便,①有精度問題 ②這裡保證整數解,沒必要浮點 ③整數取模方便)

所以採用整數的形式

如何行變換相消去呢?

採用公倍數的形式

對於最後求未知數(ans陣列)

可以採用兩種方式

1.若矩陣化成的是對角型 則可以直接求解(若取模,則要求逆元;若模數很小,可以直接迴圈,如本題)

2.若矩陣化成的是上三角型 則回代法求解(若取模,則要求逆元;若模數很小,可以直接迴圈,如本題)

//高斯消元 時間複雜度o(n^3) 使用整型計算

//公倍數法 適用於只需要整數解、取模的情況

#include

#include

#include

#include

#include

#include

using

namespace

std;

const

int maxn=101;

long

long det;//行列式的值

int mod;

//特別適合於行列式求值 取模操作 (除法要求逆元)

//不化成對角而是上三角 因為涉及到取模 要保留一些資訊

inline

int solve(int a[maxn],bool l,int ans,const

int &n,const

int &m)

//從a[r][i]這乙個元素開始 往下的每個元素都是0了 所以這個元素xi是自由變元 i+1跳過即可

if(a[r][i]==0)

for(int j=0;j//j是行數 從0開始 是對角 不是上三角 這樣不要從下往上回代

if(j!=r&&a[j][i])

}l[i]=true,++r;

}//輸出階梯型矩陣

// for(int j=0;j

// for(int k=0;k<=n;++k)

// coutdet=1;

for(int i=0;i//檢查是否無解

for(int i=n-res;iif(a[i][n]) return -1;

}for(int i=0;iif(l[i])}}

}return res;//返回自由變元數

}int b[maxn][maxn]=,,,

,,,,

,};int main()

res=solve(a,l,ans,n,m);

// for(int i=0;i

// if(l[i]&&(ans[i])%4!=0) cout<<'x'// cout ahu;

for(int i=0;iif(l[i]&&ans[i]%4!=0)}}

for(multiset

::iterator it=ahu.begin();it!=ahu.end();it++) cout

<<*(it)<<' ';

return

0;}

//下面是有區別的**部分

//gauss消元 行相消

for(int j=r+1;j//j是行數 從r+1開始 是上三角 不是對角 這樣要從下往上回代

if(a[j][i])

}l[i]=true,++r;

}//下面求結果 不考慮自由變元

for(int i=n-1;i>=0;--i)

}//列舉求值 因為題目要求最短的序列 即x盡量小 所以有滿足的直接break就行

//這裡可能出現多解的情況 一般情況是解同余式ax同餘c(mod m)

for(ans[i]=0;ans[i]if((ans[i]*a[i][i]+mod)%mod==temp) break;

}

Gauss 高斯消元

ans 直接用初中的解方程組的方法呀!沒錯,直接暴力加減消元。那什麼是 高斯消元 說白了,就是普通的加減消元罷了。本人再考場上打了乙個暴力解方程,大家都說要高斯消元,弄得我方極了,最後才發現我打的暴力就是高斯消元 選其中乙個方程 將其他方程的其中乙個元與選出的方程統一係數 將選出的方程與其他方程相減...

POJ1830 開關問題 Gauss消元

有n個相同的開關,每個開關都與某些開關有著聯絡,每當你開啟或者關閉某個開關的時候,其他的與此開關相關聯的開關也會相應地發生變化,即這些相聯絡的開關的狀態如果原來為開就變為關,如果為關就變為開。你的目標是經過若干次開關操作後使得最後n個開關達到乙個特定的狀態。對於任意乙個開關,最多只能進行一次開關操作...

POJ 1830 開關問題(Gauss 消元)

time limit 1000ms memory limit 30000k total submissions 7726 accepted 3032 description 有n個相同的開關,每個開關都與某些開關有著聯絡,每當你開啟或者關閉某個開關的時候,其他的與此開關相關聯的開關也會相應地發生變化...