}
return 0;
}
kmp字符串
#include
using namespace std;
const int N=100010,M=1000010;
int n,m;
int ne[N];//ne[i]=j表示的是p字符串中以i為終點(diǎn)的子串p[1~j]=p[i-j+1,i] 是相等的
char s[M],p[N];//s是母串,p是子串
int main(){
cin>>n>>p+1>>m>>s+1;//下標(biāo)從1開始
//求ne數(shù)組
for(int i=2,j=0;i<=n;i++){
while(j&&p[i]!=p[j+1]) j=ne[j];
if(p[i]==p[j+1]) j++;
ne[i]=j;
}
//匹配過程
for(int i=1,j=0;i<=m;i++){
while(j&&s[i]!=p[j+1]) j=ne[j];
if(s[i]==p[j+1]) j++;
if(j==n){
cout<j=ne[j];
}
}
return 0;
}
字典樹(樹狀數(shù)組)
字符串統(tǒng)計(jì)
#include
using namespace std;
const int N=100010;
/*
字典樹,樹狀數(shù)組 son存的是本字母的下標(biāo),也是下個(gè)字母的一維(指向下一個(gè)字母),二維是本字母的ascll碼,
idx下標(biāo),一維從1開始
*/
int son[N][26],cnt[N],idx;
char str[N];
void insert(char *str){
int p=0;
for(int i=0;str[i];i++){//字符串遍歷
int u=str[i]-'a';
if(!son[p][u]) son[p][u]=++idx;
p=son[p][u];
}
cnt[p]++;
}
int query(char *str){
int p=0;
for(int i=0;str[i];i++){
int u=str[i]-'a';
if(!son[p][u]) return 0;
p=son[p][u];
}
return cnt[p];
}
int main(){
int n;
cin>>n;
while(n--){
char op[2];
scanf("%s%s",op,str);
if(*op=='I') insert(str);//第一個(gè)字符
else printf("%d\n",query(str));
}
return 0;
}
最大異或?qū)?/p>
/*
最大異或?qū)€是利用樹狀數(shù)組和位運(yùn)算的知識(shí)
*/
#include
#include
using namespace std;
const int N=100010,M=3100010;
int n;
int a[N],son[M][2],idx;
void insert(int x){
int p=0;
for(int i=30;i>=0;i--){
int &s=son[p][x>>i&1];
if(!s) s=++idx;
p=s;
}
}
int search(int x){
int p=0,res=0;
for(int i=30;i>=0;i--){
int s=x>>i&1;
if(son[p][!s]){
res+=1<
p=son[p][!s];
}
else p=son[p][s];
}
return res;
}
int main(){
cin>>n;
for(int i=0;icin>>a[i];
insert(a[i]);
}
int res=0;
for(int i=0;icout<return 0;
}
并查集
合并集合
/*
合并集合
*/
#include
#include
using namespace std;
const int N=100010;
int p[N];
//這個(gè)函數(shù)本質(zhì)是找到節(jié)點(diǎn)x的祖宗節(jié)點(diǎn),并且路徑壓縮了,使得路徑上的所有點(diǎn)都指向祖宗節(jié)點(diǎn)
int find(int x){
if(p[x]!=x) p[x]=find(p[x]);//讓x的父節(jié)點(diǎn)指向父節(jié)點(diǎn)的父節(jié)點(diǎn),一直遞歸,直到p[x]是x的祖宗節(jié)點(diǎn)
return p[x];
}
int main(){
int n,m;
cin>>n>>m;
for(int i=0;i>n;i++) p[i]=i;//初始化,使每個(gè)點(diǎn)父節(jié)點(diǎn)都指向自己
while(m--){
char op[2];
int a,b;
cin>>op>>a>>b;
if(*op=='M') p[find(a)]=find(b);//a的父節(jié)點(diǎn)指向b,讓b成為a的父節(jié)點(diǎn)
else{
if(find(a)==find(b)) puts("YES");
else puts("NO");
}
}
return 0;
}
連通塊中點(diǎn)的數(shù)量
/*
連通塊中的數(shù)量,再開一個(gè)數(shù)組存儲(chǔ)連通塊點(diǎn)數(shù),一般是祖宗節(jié)點(diǎn)的cnt.并查集加點(diǎn)數(shù)維護(hù)
調(diào)試小技巧,一般輸入輸出有問題,先看for循環(huán)的輸入輸出
*/
#include
#include
using namespace std;
const int N=100010;
int p[N],cnt[N];
//這個(gè)函數(shù)本質(zhì)是找到節(jié)點(diǎn)x的祖宗節(jié)點(diǎn),并且路徑壓縮了,使得路徑上的所有點(diǎn)都指向祖宗節(jié)點(diǎn)
int find(int x){
if(p[x]!=x) p[x]=find(p[x]);//讓x的父節(jié)點(diǎn)指向父節(jié)點(diǎn)的父節(jié)點(diǎn),一直遞歸,直到p[x]是x的祖宗節(jié)點(diǎn)
return p[x];
}
int main(){
int n,m;
cin>>n>>m;
for(int i=0;ip[i]=i;
cnt[i]=1;
}
while(m--){
string op;//字符串輸入操作信號(hào)
int a,b;
cin>>op;
if(op=="C"){
cin>>a>>b;
a=find(a),b=find(b);
if(a!=b){
p[a]=b;
cnt[b]+=cnt[a];
}
}
else if(op=="Q1"){
cin>>a>>b;
if(find(a)==find(b)) puts("YES");
else puts("NO");
}
else{
cin>>a;
cout<}
}
return 0;
}
食物鏈
/*
食物鏈,并查集加距離維護(hù)
A←B←C←A: A吃B, B吃C, C吃A,若距離%3余數(shù)為0同類,1B被根節(jié)點(diǎn)吃,2C吃根節(jié)點(diǎn)
*/
#include
#include
using namespace std;
const int N=500010;
int p[N],d[N];//d數(shù)組存放離父節(jié)點(diǎn)距離,路徑壓縮優(yōu)化完就是到根節(jié)點(diǎn)距離
//遞歸調(diào)用,找到根節(jié)點(diǎn),完成路徑壓縮+尋找根節(jié)點(diǎn)
int find(int x){
if(p[x]!=x){
int t=find(p[x]);//向上搜索根節(jié)點(diǎn)
d[x]+=d[p[x]];//到根節(jié)點(diǎn)的距離等于到父節(jié)點(diǎn)的距離+父節(jié)點(diǎn)到根節(jié)點(diǎn)的距離
p[x]=t;//父節(jié)點(diǎn)變根節(jié)點(diǎn)
}
return p[x];
}
int main(){
int n,m,res=0;
cin>>n>>m;
for(int i=1;i<=n;i++){//初始化,使每個(gè)點(diǎn)父節(jié)點(diǎn)都指向自己
p[i]=i;
}
while(m--){
int op,x,y;
cin>>op>>x>>y;
if(x>n||y>n) res++;
else{
int px=find(x),py=find(y);
if(op==1){//x,y是同類的判斷。x,y到根節(jié)點(diǎn)距離相等
if(px==py&&(d[x]-d[y])%3) res++;//在同一個(gè)集合中,但不是同類關(guān)系,錯(cuò)誤
else if(px!=py){//沒在一個(gè)集合,加在一個(gè)集合中,維持距離是同類 ****
p[px]=py;
d[px]=d[y]-d[x];
}
}
else{//判斷x吃y,若x吃y,則要x,y在同一個(gè)集合中,x到根節(jié)點(diǎn)的距離要比y小1
if(px==py&&(d[y]-1-d[x])%3) res++;//在同一集合中,但不是x吃y的關(guān)系
else if(px!=py){
p[px]=py;
d[px]=d[y]-d[x]-1;
}
}
}
}
cout<return 0;
}
堆
堆排序
/*
堆排序
*/
#include
#include
using namespace std;
const int N=500010;
int n,m;
int h[N],cnt;//cnt表示堆中最后一個(gè)數(shù)的下標(biāo),從1開始
void down(int u){//傳堆的下標(biāo)
int t=u;//t為最小數(shù)的下標(biāo)
if(u*2<=cnt&&h[u*2]if(u*2+1<=cnt&&h[u*2+1]if(u!=t){
swap(h[u],h[t]);
down(t);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>h[i];
cnt=n;
for(int i=n/2;i>0;i--) down(i);//整理成小根堆
while(m--){
cout<h[1]=h[cnt--];
down(1);
}
puts("");
return 0;
}
模擬堆
/*
模擬堆。要重寫交換函數(shù)
*/
#include
#include
#include
using namespace std;
const int N=500010;
int n,m;//m代表第m個(gè)插入的數(shù)
int h[N],ph[N],hp[N],cnt;//cnt表示堆中最后一個(gè)數(shù)的下標(biāo),從1開始
//ph[k]:第k個(gè)插入的數(shù)在堆中的編號(hào),hp[i]:在堆中編號(hào)為i的位置是第幾個(gè)插入的
void heap_swap(int a,int b){//a,b表示堆的編號(hào)(下標(biāo))
swap(ph[hp[a]],ph[hp[b]]);
swap(hp[a],hp[b]);
swap(h[a],h[b]);
}
void down(int u){//傳堆的下標(biāo)
int t=u;//t為最小數(shù)的下標(biāo)
if(u*2<=cnt&&h[u*2]if(u*2+1<=cnt&&h[u*2+1]if(u!=t){
heap_swap(u,t);
down(t);
}
}
void up(int u){
while(u/2&&h[u]heap_swap(u,u/2);
u=u/2;
}
}
int main(){
cin>>n;
while(n--){
char op[5];
int k,x;
cin>>op;
if(!strcmp(op,"I")){//若op定義為string,則可以用op=="I"判斷
cin>>x;
cnt++;
m++;
ph[m]=cnt,hp[cnt]=m;
h[cnt]=x;
up(cnt);
}
else if(!strcmp(op,"PM")) cout<else if(!strcmp(op,"DM")){
heap_swap(1,cnt);
cnt--;
down(1);
}
else if(!strcmp(op,"D")){
cin>>k;//刪除第k個(gè)插入的數(shù)
k=ph[k];//變?yōu)橄聵?biāo)編號(hào)
heap_swap(cnt,k);
cnt--;
up(k);
down(k);
}
else{
cin>>k>>x;
k=ph[k];
h[k]=x;
up(k);
down(k);
}
}
return 0;
}
哈希表
模擬散列表
開放尋址法
/*
模擬散列表。開放尋址法,用x余數(shù)來存放,可以減小范圍
*/
#include
#include
#include
using namespace std;
const int N=200003,null=0x3f3f3f3f;//N最好是質(zhì)數(shù)
int h[N];
int find(int x){//找到x的所在位置下標(biāo)或者x應(yīng)該存放位置下標(biāo)
int t=(x%N+N)%N;
while(h[t]!=null&&h[t]!=x){
t++;
if(t==N) t=0;
}
return t;
}
int main(){
memset(h,0x3f,sizeof h);
int n;
cin>>n;
while(n--){
char op[2];
int x;
cin>>op>>x;
if(*op=='I') h[find(x)]=x;
else{
if(h[find(x)]==null) puts("NO");
else puts("YES");
}
}
return 0;
}
拉鏈法
/*
模擬散列表。拉鏈法
*/
#include
#include
#include
using namespace std;
const int N=100003;//N最好是質(zhì)數(shù)
int h[N],e[N],ne[N],idx;
bool find(int x){//判斷鏈表中是否有x這個(gè)數(shù)
int t=(x%N+N)%N;
for(int i=h[t];~i;i=ne[i]){
if(e[i]==x)
return true;
}
return false;
}
void insert(int x){//插入x到相應(yīng)鏈表中
int t=(x%N+N)%N;
e[idx]=x,ne[idx]=h[t],h[t]=idx++;//頭插法
}
int main(){
memset(h,-1,sizeof h);
int n;
cin>>n;
while(n--){
char op[2];
int x;
cin>>op>>x;
if(*op=='I') insert(x);
else{
if(!find(x)) puts("NO");
else puts("YES");
}
}
return 0;
}
字符串哈希
/*
字符串哈希
*/
#include
#include
#include
using namespace std;
typedef unsigned long long ull;
const int N=100010,P=131; //p進(jìn)制或取13331
int n,m;
char str[N];
ull h[N],p[N];//h[i]表示前i為和,從右往左的前綴和,像一般的數(shù)字一樣,左邊是高位。
//p[i]表示第i位的權(quán)重。p[i]=p^i。p[0]=1。
ull get(int l,int r){
return h[r]-h[l-1]*p[r-l+1];
}
int main(){
cin>>n>>m>>str+1;
p[0]=1;
for(int i=1;i<=n;i++){
h[i]=h[i-1]*P+str[i];//前i個(gè)字符轉(zhuǎn)換成的數(shù)
p[i]=p[i-1]*P;//表示P的i次方。
}
while(m--){//m次詢問
int l1,r1,l2,r2;
cin>>l1>>r1>>l2>>r2;
if(get(l1,r1)==get(l2,r2)) puts("YES");
else puts("NO");
}
return 0;
}
搜索和圖論
dfs
排序數(shù)字
/*
排列數(shù)字
*/
#include
#include
#include
using namespace std;
typedef unsigned long long ull;
const int N=10;
int n;
int path[N],st[N];
void dfs(int u){
if(u==n){
for(int i=0;icout<puts("");
}
for(int i=1;i<=n;i++){
if(!st[i]){
path[u]=i;
st[i]=true;
dfs(u+1);
st[i]=false;
}
}
}
int main(){
cin>>n;
dfs(0);
return 0;
}
n皇后問題
直接考慮
#include
using namespace std;
const int N = 10;
int n;
bool row[N], col[N], dg[N * 2], udg[N * 2];
char g[N][N];
void dfs(int x, int y, int s)
{
if (s > n) return;
if (y == n) y = 0, x ++ ;
if (x == n)
{
if (s == n)
{
for (int i = 0; i < n; i ++ ) puts(g[i]);
puts("");
}
return;
}
g[x][y] = '.';
dfs(x, y + 1, s);
if (!row[x] && !col[y] && !dg[x + y] && !udg[x - y + n])
{
row[x] = col[y] = dg[x + y] = udg[x - y + n] = true;
g[x][y] = 'Q';
dfs(x, y + 1, s + 1);
g[x][y] = '.';
row[x] = col[y] = dg[x + y] = udg[x - y + n] = false;
}
}
int main()
{
cin >> n;
dfs(0, 0, 0);
return 0;
}
優(yōu)化情況
/*
n皇后問題
*/
#include
#include
#include
using namespace std;
const int N=10;
int n;
int p[N][N],col[N],dg[N*2],udg[N*2];
char g[N][N];//char類型
void dfs(int u,int t){
if(t>n) return;//剪枝
if(u==n){//我們所需要的結(jié)果
if(t==n){
for(int i=0;iputs(g[i]);//輸出一串并自動(dòng)換行
}
puts("");
return;
}
for(int i=0;iif(!col[i]&&!dg[i-u+n]&&!udg[i+u]){
g[u][i]='Q';
col[i]=dg[i-u+n]=udg[i+u]=true;
dfs(u+1,t+1);
col[i]=dg[i-u+n]=udg[i+u]=false;
g[u][i]='.';
}
}
}
int main(){
cin>>n;
for(int i=0;ifor(int j=0;jg[i][j]='.';
dfs(0,0);
return 0;
}
總結(jié): 1.dfs的本質(zhì)是利用遞歸這種思想(遞歸內(nèi)部用棧實(shí)現(xiàn)),用for來遍歷此層的所有可能的取值情況,然后把已經(jīng)取值的情況標(biāo)記,避免下面遞歸再用此值,再進(jìn)入下層繼續(xù)遞歸,在調(diào)用遞歸結(jié)束后取消標(biāo)記回溯,進(jìn)入此層的下個(gè)可能情況
2.dfs的一般步驟是退出遞歸的條件,有剪枝和遞歸到最后一層的下一層可取結(jié)果這兩種情況。然后就是每層(此層)可取的可能情況枚舉(多個(gè)用for循環(huán),兩個(gè)直接枚舉了),對(duì)于取完一個(gè)情況進(jìn)入下層遞歸前需要標(biāo)記這個(gè)情況避免影響下面遞歸,遞歸執(zhí)行完后再進(jìn)行回溯,需要把標(biāo)記取消
bfs
走迷宮
/*
走迷宮
*/
#include
#include
#include
#include
using namespace std;
typedef pair pii;
const int N=110;
int n,m;
int g[N][N],d[N][N];
int bfs(){
queue q;
memset(d,-1,sizeof d);
d[0][0]=0;
q.push({0,0});
int dx[4]={-1,0,1,0},dy[4]={0,-1,0,1};
while(q.size()){
auto t=q.front();
q.pop();
for(int i=0;i<4;i++){
int x=t.first+dx[i],y=t.second+dy[i];
if(x>=0&&x=0&&yd[x][y]=d[t.first][t.second]+1;
q.push({x,y});
}
}
}
return d[n-1][m-1];
}
int main(){
cin>>n>>m;
for(int i=0;ifor(int j=0;jcin>>g[i][j];
}
cout<return 0;
}
八數(shù)碼
/*
八數(shù)碼
*/
#include
#include
#include
#include
#include
using namespace std;
string state;
int bfs(){
queue q;
unordered_map d;
string end="12345678x";
q.push(state);
d[state]=0;
int dx[4]={-1,0,1,0},dy[4]={0,-1,0,1};
while(q.size()){
auto t=q.front();
q.pop();
if(t==end) return d[t];
int di=d[t];
int k=t.find('x');//字符串查找下標(biāo)函數(shù)
int x=k/3,y=k%3;
for(int i=0;i<4;i++){
int a=x+dx[i],b=y+dy[i];
if(a>=0&&a<3&&b>=0&&b<3){
swap(t[a*3+b],t[k]);//交換字符串中下標(biāo)為a*3+b與k的字符
if(!d.count(t)){//map中判斷key是否存在
d[t]=di+1;//此時(shí)的t為交換后的字符串(另一種狀態(tài))
q.push(t);
}
swap(t[a*3+b],t[k]);//交換回來進(jìn)行下次移動(dòng),不影響下次
}
}
}
return -1;
}
int main(){
char s[2];//這個(gè)挺好用
for(int i=0;i<9;i++){
cin>>s;
state+=*s;
}
cout<return 0;
}
總結(jié): bfs的本質(zhì)是利用隊(duì)列,有最短路的性質(zhì)。一般步驟是將滿足條件的情況入隊(duì),有距離數(shù)組需要初始化的初始化,然后while隊(duì)列不空,取隊(duì)頭并將其出隊(duì),再將于隊(duì)頭有關(guān)的情況或者隊(duì)頭的下一步的所有情況入隊(duì),最后返回我們需要的“情況。
樹圖的搜索
dfs樹的重心
/*
樹的重心。用dfs來求
*/
#include
#include
#include
#include
using namespace std;
const int N=100010,M=N*2;
int n;
int h[N],e[N],ne[M],idx;
int ans=N;//所需要的答案,每個(gè)子樹個(gè)數(shù)最大的最小值
bool st[N];//標(biāo)記已經(jīng)走過的點(diǎn)
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int dfs(int u){//求以u(píng)為根的所有子樹的節(jié)點(diǎn)個(gè)數(shù),包括根節(jié)點(diǎn)
int res=0,sum=1;//res求子樹個(gè)數(shù)最大值,sum是包括根節(jié)點(diǎn)的總節(jié)點(diǎn)數(shù)
st[u]=true;//判斷那個(gè)是重心,每個(gè)點(diǎn)都遍歷到
for(int i=h[u];~i;i=ne[i]){//求res和sum
int j=e[i];
if(!st[j]){
int s=dfs(j);//s是以j為根節(jié)點(diǎn)的總節(jié)點(diǎn)個(gè)數(shù)
res=max(res,s);//求最大的子樹節(jié)點(diǎn)數(shù)
sum+=s;
}
}
res=max(res,n-sum);//求最大
ans=min(ans,res);//答案是res的最小值
return sum;
}
int main(){
cin>>n;
memset(h,-1,sizeof h);
for(int i=0;iint a,b;
cin>>a>>b;
add(a,b),add(b,a);//樹無(wú)向邊
}
dfs(1);
cout<return 0;
}
圖中點(diǎn)的層次
/*
圖中點(diǎn)的層次。bfs來求
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=100010,M=N*2;
//在上面定義的一些數(shù)組記得初始化
int n,m;
int h[N],e[N],ne[M],idx;
int d[N];//存儲(chǔ)每個(gè)點(diǎn)的層次,d[i]表示點(diǎn)i所在層次
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int bfs(){
memset(d,-1,sizeof d);
d[1]=0;
queue q;
q.push(1);
while(q.size()){
auto t=q.front();
q.pop();
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(d[j]==-1){
d[j]=d[t]+1;
q.push(j);
}
}
}
return d[n];
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=0;iint a,b;
cin>>a>>b;
add(a,b);
}
cout<return 0;
}
拓?fù)渑判?/p>
/*
拓?fù)渑判?。用bfs來求,手寫隊(duì)列
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=100010,M=N*2;
//在上面定義的一些數(shù)組記得初始化
int n,m;
int h[N],e[N],ne[M],idx;
int d[N];//存儲(chǔ)每個(gè)點(diǎn)的入度
int q[N],hh,tt=-1;//手寫隊(duì)列
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool topsort(){
for(int i=1;i<=n;i++){
if(!d[i])
q[++tt]=i;
}
while(hh<=tt){
auto t=q[hh++];
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(--d[j]==0)
q[++tt]=j;
}
}
if(ttelse return true;
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=0;iint a,b;
cin>>a>>b;
add(a,b);//a→b
d[b]++;//b點(diǎn)入度加1
}
if(!topsort()) puts("-1");
else{
for(int i=0;icout<puts("");
}
return 0;
}
最短路算法
單源最短路
樸素版dijkstra
/*
樸素版dijkstra。用領(lǐng)接矩陣來表示
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=510;
//在上面定義的一些數(shù)組記得初始化
int n,m;
int g[N][N];//領(lǐng)接矩陣來存儲(chǔ)圖
int d[N];//存儲(chǔ)每個(gè)點(diǎn)到源點(diǎn)的距離
bool st[N];//判斷點(diǎn)是否在s集合中。s集合表示已經(jīng)確定了最短路的點(diǎn)集
int dj(){
//初始化
memset(d,0x3f,sizeof d);
d[1]=0;
//將所有點(diǎn)都放入s集合中,每次找到里源點(diǎn)最近的點(diǎn),然后用此點(diǎn)來更新其他點(diǎn)
for(int i=0;iint t=-1;
for(int j=1;j<=n;j++){
if(!st[j]&&(d[j]t=j;
}
}
st[t]=true;
for(int j=1;j<=n;j++){
if(d[j]>d[t]+g[t][j])
d[j]=d[t]+g[t][j];
}
}
if(d[n]==0x3f3f3f3f) return -1;
return d[n];
}
int main(){
cin>>n>>m;
memset(g,0x3f,sizeof g);
while(m--){
int a,b,c;
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);//重邊用最短的路徑
}
cout<return 0;
}
堆優(yōu)化版dijsktra
/*
堆優(yōu)化版dijkstra。用小根堆優(yōu)化,直接取每次距離源點(diǎn)最近的點(diǎn)
*/
#include
#include
#include
#include
#include
using namespace std;
typedef pair pii;
const int N=1e6+10;
int n,m;
int h[N],e[N],ne[N],w[N],idx;//鄰接表存儲(chǔ)
int d[N];//每個(gè)點(diǎn)到源點(diǎn)距離
bool st[N];
void add(int a,int b,int c){
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
int dj(){
//初始化
memset(d,0x3f,sizeof d);
d[1]=0;
priority_queue,greater > q;
q.push({0,1});
while(q.size()){
auto t=q.top();
q.pop();
int di=t.first,v=t.second;
if(st[v]) continue;
st[v]=true;
for(int i=h[v];~i;i=ne[i]){
int j=e[i];
if(d[j]>d[v]+w[i]){//注意是w[i]而不是w[j],i是下標(biāo),j是點(diǎn)
d[j]=d[v]+w[i];
if(!st[j])
q.push({d[j],j});
}
}
}
if(d[n]==0x3f3f3f3f) return -1;
return d[n];
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof h);
while(m--){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);//有向圖
}
cout<return 0;
}
bellman-ford算法(可存在負(fù)權(quán)邊)
/*
有邊數(shù)限制的最短路,bellman-ford算法
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=510,M=10010;
struct Edge{
int a,b,c;
}e[M];
int n,m,k;//點(diǎn)數(shù),邊數(shù),限制邊數(shù)
int d[N];
int last[N];//上層限制邊數(shù)條件下,各點(diǎn)到源點(diǎn)距離
void bellman_ford(){
memset(d,0x3f,sizeof d);
d[1]=0;
for(int i=0;imemcpy(last,d,sizeof d);//用memset轉(zhuǎn)換無(wú)效,上層邊數(shù)限制
for(int j=0;jint a=e[j].a,b=e[j].b,c=e[j].c;
if(d[b]>last[a]+c){
d[b]=last[a]+c;
}
}
}
}
int main(){
cin>>n>>m>>k;
for(int i=0;iint a,b,c;
cin>>a>>b>>c;
e[i]={a,b,c};
}
bellman_ford();
if(d[n]>0x3f3f3f3f/2) puts("impossible");//存在負(fù)權(quán)可能會(huì)使INF變小
else cout<return 0;
}
spfa算法(可存在負(fù)權(quán)邊)
spfs是bellman-ford算法用隊(duì)列優(yōu)化的算法,每次松弛不用每各點(diǎn)都判斷更新,只有某個(gè)點(diǎn)的前驅(qū)節(jié)點(diǎn)更新才會(huì)導(dǎo)致改點(diǎn)更新,st數(shù)組來表示被更新的點(diǎn),入隊(duì)true,出隊(duì)false,可逆。 1.求最短路
/*
spfa算法求最短路,用鄰接表存儲(chǔ),用隊(duì)列來優(yōu)化
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=10010;
int n,m;//點(diǎn)數(shù),邊數(shù)
int h[N],e[N],ne[N],w[N],idx;//鄰接表第一反應(yīng)要記得初始化h數(shù)組
int d[N];
bool st[N];//表示被更新的點(diǎn),而不是判斷是否在s集合中
void add(int a,int b,int c){
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void spfa(){
memset(d,0x3f,sizeof d);
d[1]=0;
queue q;
q.push(1);
st[1]=true;
while(q.size()){
auto t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(d[j]>d[t]+w[i]){
d[j]=d[t]+w[i];
if(!st[j]){
q.push(j);
st[j]=true;
}
}
}
}
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof h);//不要忘了初始化,不然沒有輸出程序一直運(yùn)行。
for(int i=0;iint a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
spfa();
if(d[n]==0x3f3f3f3f) puts("impossible");//存在負(fù)權(quán)可能會(huì)使INF變小
else cout<return 0;
}
2.求是否存在負(fù)環(huán)
/*
spfa算法求是否有負(fù)權(quán)回路,用鄰接表存儲(chǔ),用隊(duì)列來優(yōu)化
要多一個(gè)cnt數(shù)組來存儲(chǔ)到達(dá)每個(gè)點(diǎn)的邊數(shù),若邊數(shù)大于n-1則說明有負(fù)權(quán)回路
然后全部點(diǎn)也要先入隊(duì)
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=10010;
int n,m;//點(diǎn)數(shù),邊數(shù)
int h[N],e[N],ne[N],w[N],idx;//鄰接表第一反應(yīng)要記得初始化h數(shù)組
int d[N];
int cnt[N];//表示到達(dá)i點(diǎn)所經(jīng)過的邊數(shù)
bool st[N];//表示被更新的點(diǎn),而不是判斷是否在s集合中
void add(int a,int b,int c){
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
bool spfa(){
memset(d,0x3f,sizeof d);
d[1]=0;
queue q;
for(int i=i;i<=n;i++){//將所有的點(diǎn)全部入隊(duì)
q.push(i);
st[i]=true;
}
while(q.size()){
auto t=q.front();
q.pop();
st[t]=false;
for(int i=h[t];~i;i=ne[i]){
int j=e[i];
if(d[j]>d[t]+w[i]){
d[j]=d[t]+w[i];
cnt[j]=cnt[t]+1;
if(cnt[j]>n-1) return true;
if(!st[j]){
q.push(j);
st[j]=true;
}
}
}
}
return false;
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof h);//不要忘了初始化,不然沒有輸出程序一直運(yùn)行。
for(int i=0;iint a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
if(spfa()) puts("YES");//存在負(fù)權(quán)可能會(huì)使INF變小
else puts("NO");
return 0;
}
多源最短路
Floyd算法
/*
Floyd算法求多源回路問題。點(diǎn)的取值范圍三個(gè)for循環(huán)
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=210,inf=1e9;
int n,m;//點(diǎn)數(shù),邊數(shù)
int d[N][N];//d[x][y]表示點(diǎn)x到點(diǎn)y的距離
void floyd(){
for(int k=1;k<=n;k++)//點(diǎn)的取值范圍
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int Q;
cin>>n>>m>>Q;
//初始化距離
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) d[i][j]=0;
else d[i][j]=inf;
for(int i=0;iint a,b,c;
cin>>a>>b>>c;
d[a][b]=min(d[a][b],c);
}
floyd();
while(Q--){
int a,b;
cin>>a>>b;
int t=d[a][b];
if(t>inf/2) puts("impossible");
else cout<}
return 0;
}
總結(jié):距離數(shù)組記得初始化,圖的表示方式也要記得初始化。 然后h數(shù)組沒有初始化,輸完數(shù)據(jù)不管怎么按都沒有反應(yīng),也不會(huì)結(jié)束,程序會(huì)一直執(zhí)行。切記要初始化為-1。
最小生成樹
prim
/*
prim算法求最小生成樹的權(quán)值
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=210,inf=0x3f3f3f3f;
int n,m; //點(diǎn)邊
int g[N][N];//領(lǐng)接矩陣存儲(chǔ)
int d[N];//每個(gè)點(diǎn)到s的距離
bool st[N];//判斷是否是已經(jīng)加入s的點(diǎn)
int prim(){
memset(d,0x3f,sizeof d);
d[1]=0;
int res=0;//最小生成樹的權(quán)值
for(int i=0;iint t=-1;
for(int j=1;j<=n;j++){
if(!st[j]&&(t==-1||d[t]>d[j])){
t=j;
}
}
if(i) res+=d[t];//先累加在更新
if(i&&d[t]==inf) return inf;
st[t]=true;
for(int j=1;j<=n;j++) d[j]=min(d[j],g[t][j]);
}
return res;
}
int main(){
cin>>n>>m;
memset(g,0x3f,sizeof g);
while(m--){
int a,b,c;
cin>>a>>b>>c;
g[a][b]=min(g[a][b],c);
}
int t=prim();
if(t==inf) puts("impossible");
else cout<return 0;
}
kruskal
/*
kruskal算法求最小生成樹的權(quán)值
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=100010,M=200010,inf=0x3f3f3f3f;
int n,m; //點(diǎn)邊
int p[N];//并查集
struct Edge{
int a,b,w;
bool operator<(const Edge&W) const{
return w}
}e[M];
int find(int x){
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int kruskal(){
sort(e,e+m);
int cnt=0;//積累的邊數(shù)
int res=0;//權(quán)值
for(int i=0;iint a=e[i].a,b=e[i].b,w=e[i].w;
if(find(a)!=find(b)){
p[find(a)]=find(b);
cnt++;
res+=w;
}
}
if(cntelse return res;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
p[i]=i;
}
for(int i=0;iint a,b,w;
cin>>a>>b>>w;
e[i]={a,b,w};
}
int t=kruskal();
if(t==inf) puts("impossible");
else cout<return 0;
}
二分圖
染色法判斷二分圖
/*
染色法判斷二分圖,用dfs染色
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=100010,M=200010;
int n,m; //點(diǎn)邊
int h[N],e[M],ne[M],idx;
int color[N];//標(biāo)記每個(gè)點(diǎn)的顏色
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool dfs(int u,int c){//將u點(diǎn)染成c顏色,并將與u點(diǎn)有關(guān)的也染成相應(yīng)顏色
color[u]=c;
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(!color[j]){
if(!dfs(j,3-c)) return false;
}else if(color[j]==c){//與u相連的點(diǎn)顏色和u染成一樣不行
return false;
}
}
return true;
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof h);
while(m--){
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
}
bool flag=true;
for(int i=1;i<=n;i++){
if(!color[i]){
if(!dfs(i,1)){
flag=false;
break;
}
}
}
if(flag) puts("YES");
else puts("NO");
return 0;
}
二分圖的最大匹配
/*
染色法判斷二分圖,用dfs染色
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=510,M=100010;
int n1,n2,m,res; //點(diǎn)邊
int h[N],e[M],ne[M],idx;
int match[N];//妹子是否與左邊匹配了,匹配了的話就是左邊的數(shù)
bool st[N];//判斷左邊對(duì)妹子是否考慮了
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool find(int x){//左邊的點(diǎn)x嘗試匹配右邊的妹子
for(int i=h[x];~i;i=ne[i]){
int j=e[i];//j點(diǎn)是右邊的
if(!st[j]){
st[j]=true;
if(!match[j]||find(match[j])){
match[j]=x;
return true;
}
}
}
return false;
}
int main(){
cin>>n1>>n2>>m;
memset(h,-1,sizeof h);
while(m--){
int a,b;
cin>>a>>b;
add(a,b);
}
for(int i=1;i<=n1;i++){
memset(st,false,sizeof st);//每個(gè)左邊都要初始化一下st數(shù)組
if(find(i)) res++;
}
cout<return 0;
}
數(shù)學(xué)知識(shí)
質(zhì)數(shù)
試除法判斷質(zhì)數(shù)
/*
試除法判斷質(zhì)數(shù)。質(zhì)數(shù)大于1,除了1只有本身這兩個(gè)約數(shù)
*/
#include
#include
#include
#include
#include
using namespace std;
bool is_prime(int x){
if(x<2) return false;
for(int i=2;i<=x/i;i++){
if(x%i==0)
return false;
}
return true;
}
int main(){
int n;
cin>>n;
while(n--){
int x;
cin>>x;
if(is_prime(x)) puts("YES");
else puts("NO");
}
return 0;
}
分解質(zhì)因數(shù)
/*
分解質(zhì)因數(shù)
*/
#include
#include
#include
#include
#include
using namespace std;
void divide(int x){
for(int i=2;i<=x/i;i++){
if(x%i==0){
int res=0;
while(x%i==0){
res++;
x/=i;
}
cout<
}
}
if(x>1) cout<}
int main(){
int n;
cin>>n;
while(n--){
int x;
cin>>x;
divide(x);
}
return 0;
}
質(zhì)數(shù)篩
/*
優(yōu)化的質(zhì)數(shù)篩
若i是primes[j]倍數(shù),則s=primes[j+1]*i也是primes[j]倍數(shù),
則s就不是其最小公因數(shù)標(biāo)記的。例如12是i=6時(shí)被標(biāo)記,而不是i=4時(shí)就被標(biāo)記
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=10000;
int primes[N],cnt;
bool st[N];
void get_primes(int x){
for(int i=2;i<=x;i++){
if(!st[i]) primes[cnt++]=i;
for(int j=0;primes[j]<=x/i;j++){
st[primes[j]*i]=true;//每個(gè)非質(zhì)數(shù)都由其最小公因數(shù)(質(zhì)數(shù))標(biāo)記
if(i%primes[j]==0)
break;
}
}
}
int main(){
int n;
cin>>n;
get_primes(n);
for(int i=0;ireturn 0;
}
約數(shù)
試除法求約數(shù)
/*
試除法求約數(shù)
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=10000;
int di[N],cnt;
void get(int x){
for(int i=1;i<=x/i;i++){
if(x%i==0){
di[cnt++]=i;
if(x/i!=i)
di[cnt++]=x/i;
}
}
}
int main(){
int n;
cin>>n;
get(n);
sort(di,di+cnt);
for(int i=0;icout<return 0;
}
約數(shù)個(gè)數(shù)
/*
約數(shù)的個(gè)數(shù),首先分解質(zhì)因數(shù),如何根據(jù)每個(gè)質(zhì)因數(shù)的個(gè)數(shù)來求約數(shù)的個(gè)數(shù)
*/
#include
#include
#include
#include
#include
using namespace std;
const int N=10000;
int get(int x){
int res=0,ans=1;
for(int i=2;i<=x/i;i++){
res=0;
if(x%i==0){
while(x%i==0){
x/=i;
res++;
}
ans=(res+1)*ans;
}
}
if(x>1) ans=ans*2;
return ans;
}
int main(){
int n;
cin>>n;
int s=get(n);
cout<
return 0;
}
用數(shù)據(jù)結(jié)果unordered_map 來將質(zhì)因數(shù)和其指數(shù)記錄;
/*
約數(shù)的個(gè)數(shù),首先分解質(zhì)因數(shù),如何根據(jù)每個(gè)質(zhì)因數(shù)的個(gè)數(shù)來求約數(shù)的個(gè)數(shù)
*/
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=110,mod=1e9;
int main(){
int n;
cin>>n;
unordered_map primes;
while(n--){
int x;
cin>>x;
for(int i=2;i<=x/i;i++){
if(x%i==0){
while(x%i==0){
x/=i;
primes[i]++;
}
}
}
if(x>1) primes[x]++;
}
int res=1;
for(auto prime:primes) res=res*(prime.second+1)%mod;
cout<return 0;
}
約數(shù)之和
/*
求n個(gè)數(shù)的乘積的約數(shù)之和
約數(shù)之和,首先分解質(zhì)因數(shù),然后根據(jù)每個(gè)質(zhì)因數(shù)和其指數(shù)來求和
18=3^2*2^1;
質(zhì)因數(shù)時(shí)3,2;指數(shù)分別是2,1;
約數(shù)之和=(3^0+3^1+3^2)*(2^0+2^1);
3^0+3^1+3^2=(1+3(1+3));
*/
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=110,mod=1e9;
int main(){
int n;
cin>>n;
unordered_map primes;
while(n--){
int x;
cin>>x;
for(int i=2;i<=x/i;i++){
if(x%i==0){
while(x%i==0){
x/=i;
primes[i]++;
}
}
}
if(x>1) primes[x]++;
}
ll res=1;
for(auto prime:primes){
int a=prime.first,b=prime.second;
ll t=1;
while(b--) t=(1+a*t)%mod;//用公式可以要用費(fèi)馬小定理
res=res*t%mod;
}
cout<return 0;
}
最大共約數(shù)
/*
求最大公約數(shù)
*/
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=110,mod=1e9;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
int n;
cin>>n;
while(n--){
int a,b;
cin>>a>>b;
int t=gcd(a,b);//gcd(a,b)=gcd(b,a%b)=......=gcd(x,0)=x;求最大公約數(shù)
cout<}
return 0;
}
歐拉函數(shù)
求歐拉函數(shù)
/*
歐拉函數(shù):數(shù)n,求1~n內(nèi)與n互質(zhì)的數(shù)的個(gè)數(shù),互質(zhì)是指兩個(gè)數(shù)只有一個(gè)公約數(shù)1;
質(zhì)數(shù)n的歐拉函數(shù)是n-1;因?yàn)樵?~n內(nèi)與n互質(zhì)的數(shù)有n-1個(gè)
公式與n的公因數(shù)有關(guān)
*/
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=110,mod=1e9;
int phi(int x){
int res=x;//公式
for(int i=2;i<=x/i;i++){
if(x%i==0){
res=res*(i-1)/i;//公式
while(x%i==0) x/=i;
}
}
if(x>1) res=res*(x-1)/x;
return res;
}
int main(){
int n;
cin>>n;
while(n--){
int x;
cin>>x;
cout<}
return 0;
}
質(zhì)數(shù)篩求多個(gè)數(shù)的歐拉函數(shù)之和
用質(zhì)數(shù)篩的同時(shí)求1~n的里面的所有數(shù)的歐拉函數(shù),注意1的歐拉函數(shù)是1,要先寫出來
/*
歐拉函數(shù):數(shù)n,求1~n內(nèi)與n互質(zhì)的數(shù)的個(gè)數(shù),互質(zhì)是指兩個(gè)數(shù)只有一個(gè)公約數(shù)1;
質(zhì)數(shù)n的歐拉函數(shù)是n-1;因?yàn)樵?~n內(nèi)與n互質(zhì)的數(shù)有n-1個(gè)
公式與n的公因數(shù)有關(guān)
*/
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=1000010,mod=1e9;
int primes[N],eul[N],cnt;
bool st[N];
void get_eulors(int x){
eul[1]=1;
for(int i=2;i<=x;i++){
if(!st[i]){
primes[cnt++]=i;
eul[i]=i-1;
}
for(int j=0;primes[j]<=x/i;j++){
int s=i*primes[j];
st[s]=true;
if(i%primes[j]==0){
eul[s]=primes[j]*eul[i];
break;
}
else{
eul[s]=(primes[j]-1)*eul[i];
}
}
}
}
int main(){
int n;
cin>>n;
get_eulors(n);
int res=0;
for(int i=1;i<=n;i++) res+=eul[i];
cout<return 0;
}
快速冪
快速冪模板
/*
快速冪模板
*/
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=1000010,mod=1e9;
int qmi(int a,int b,int p){
int res=1%p;
while(b){
if(b&1) res=res*a%p;
a=a*(ll)a%p;
b>>=1;
}
return res;
}
int main(){
int n;
cin>>n;
while(n--){
int a,b,p;
cin>>a>>b>>p;//求a^b%p
cout<}
return 0;
}
快速冪求逆元(p為質(zhì)數(shù)時(shí))
/*
快速冪求逆元a*a^-1==1(%p)。當(dāng)a,p互質(zhì)時(shí),存在逆元,那么a,p的最大公約數(shù)是1=gcd(a,p)
當(dāng)p是質(zhì)數(shù)時(shí),逆元a^-1是a^p-2;
當(dāng)p不是質(zhì)數(shù)時(shí),可用擴(kuò)展歐幾里得算法,a*x+p*y=1=exgcd(a,p,x,y)可求出x
*/
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=1000010,mod=1e9;
ll qmi(int a,int b,int p){
ll res=1%p;
while(b){
if(b&1) res=(ll)res*a%p;
a=a*(ll)a%p;
b>>=1;
}
return res;
}
int main(){
int n;
cin>>n;
while(n--){
int a,p;
cin>>a>>p;//求a%p的乘法逆元,a^-1*a==1(%p) 求a^-1.
if(a%p)
cout<else//a,p不互質(zhì)則逆元不存在
puts("impossible");
}
return 0;
}
擴(kuò)展歐幾里得算法
模板
/*
擴(kuò)展歐幾里得算法模板
快速冪求逆元a*a^-1==1(%p)。當(dāng)a,p互質(zhì)時(shí),存在逆元,那么a,p的最大公約數(shù)是1=gcd(a,p)
當(dāng)p是質(zhì)數(shù)時(shí),逆元a^-1是a^p-2;
當(dāng)p不是質(zhì)數(shù)時(shí),可用擴(kuò)展歐幾里得算法,a*x+p*y=1=exgcd(a,p,x,y)可求出x,逆元為(x%p+p)%p
*/
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=1000010,mod=1e9;
int exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1,y=0;
return a;
}
int x1,y1;
int d=exgcd(b,a%b,x1,y1);
x=y1;
y=x1-(a/b)*y1;
return d;
}
int main(){
int n;
cin>>n;
while(n--){
int a,b;
cin>>a>>b;
int x,y;
int d=exgcd(a,b,x,y);//求a*x+b*y=gcd(a,b)一對(duì)x,y;結(jié)果不唯一,d是最大公約數(shù)即gcd(a,b)
cout<}
return 0;
}
線性同余方程
#include
using namespace std;
typedef long long ll;
ll exgcd(int a,int b,int &x,int &y){
if(!b){
x=1;
y=0;
return a;
}
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main(){
int n;
cin>>n;
while(n--){
int a,b,m,x,y;
cin>>a>>b>>m;
int d=exgcd(a,m,x,y);
if(b%d) cout<<"impossible"<else cout<<(long long)x*b/d%m<}
}
中國(guó)剩余定理(表達(dá)整數(shù)的奇怪方式)
表達(dá)整數(shù)的奇怪方式
#include
#include
using namespace std;
typedef long long LL;
int n;
LL exgcd(LL a, LL b, LL &x, LL &y){
if(b == 0){
x = 1, y = 0;
return a;
}
LL d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
LL inline mod(LL a, LL b){
return ((a % b) + b) % b;
}
int main(){
scanf("%d", &n);
LL a1, m1;
scanf("%lld%lld", &a1, &m1);
for(int i = 1; i < n; i++){
LL a2, m2, k1, k2;
scanf("%lld%lld", &a2, &m2);
LL d = exgcd(a1, -a2, k1, k2);
if((m2 - m1) % d){ puts("-1"); return 0; }
k1 = mod(k1 * (m2 - m1) / d, abs(a2 / d));
m1 = k1 * a1 + m1;
a1 = abs(a1 / d * a2);
}
printf("%lld\n", m1);
return 0;
}
高斯消元
解線性方程組
/*
高斯消元四步
1.找到絕對(duì)值最大的一行
2.將該行換到目前最頂端并將其首位變?yōu)?
3.用該行將下面的行首位消為0
4.判斷解條件
*/
#include
#include
#include
using namespace std;
typedef long long ll;
const int N=110;
const double eps=1e-8;
int n;//在再main函數(shù)中定義n是不一樣的
double a[N][N];//不能開得很大,一般不超過10^8
int gauss(){
int c,r;
for(c=0,r=0;cint t=r;//找此列中絕對(duì)值最大的一行
for(int i=r;iif(fabs(a[i][c])>fabs(a[t][c]))
t=i;
if(fabs(a[t][c])for(int i=c;i<=n;i++) swap(a[t][i],a[r][i]);//將絕對(duì)值最大的一行換到當(dāng)前第一行r
for(int i=n;i>=c;i--) a[r][i]/=a[r][c];//將當(dāng)前行的首位變成1
for(int i=r+1;iif(fabs(a[i][c])>eps)
for(int j=n;j>=c;j--)
a[i][j]-=a[r][j]*a[i][c];
r++;
}
if(rfor(int i=r;iif(fabs(a[i][n])>eps)
return 2;//無(wú)解
return 1;//無(wú)窮多解
}
for(int i=n-1;i>=0;i--)//唯一解
for(int j=i+1;ja[i][n]-=a[i][j]*a[j][n];
return 0;
}
int main(){
cin>>n;
for(int i=0;i