一、二分圖
1.二分圖最大匹配(匈牙利算法模板):
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
#define MAX 510
using namespace std;
int map[MAX][MAX];
int v1,v2;
int visit[MAX];
int l[MAX];
bool dfs(int x)///查找匹配
{
int i;
for(i=1;i<=v2;i++)
{
if(map[x][i]&&!visit[i])
{
visit[i]=1;
if(l[i]==0||dfs(l[i]))
{
l[i]=x;
return true;
}
}
}
return false;
}
int nmath()///計算匹配數
{
int i,ans=0;
for(i=1;i<=v1;i++)
{
memset(visit,0,sizeof(visit));
if(dfs(i))
ans++;
}
return ans;
}
int main()
{
int k,m,n,i,j,ans;
while(~scanf("%d",&k)&&k)
{
memset(map,0,sizeof(map));
memset(l,0,sizeof(l));
scanf("%d%d",&n,&m);
v1=n,v2=m;
while(k--)
{
scanf("%d%d",&i,&j);
map[i][j]=1;
}
ans=nmath();
printf("%d\n",ans);
}
return 0;
}
2.二分圖的最大帶權匹配代碼:
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
#define MAX 110
#define inf 1<<30
using namespace std;
bool s[MAX],t[MAX];///s,t,代表左右兩個集合的點是否被訪問
int w[MAX][MAX];//權值
int lx[MAX],ly[MAX];//lx,ly代表左右兩個集合中的點的頂標
int lef[MAX];///右邊點的左邊匹配點
int slack[MAX];//鬆弛度
int N[MAX],n;//N代表本來的價值(對於本體而言的)
bool dfs(int x)//深搜找增廣路
{
int i;
s[x]=true;
for(i=1;i<=n;i++)
{
if(!t[i])
{
int d=lx[x]+ly[i]-w[x][i];///鬆弛量
if(d==0)
{
t[i]=true;
if((!lef[i])||dfs(lef[i]))
{
lef[i]=x;
return true;
}
}
else
{
slack[i]=min(slack[i],d);
}
}
}
return false;
}
void update()///更新頂標值
{
int i,d=inf;
for(i=1;i<=n;i++) if(!t[i])
d=min(d,slack[i]);
for(i=1;i<=n;i++)
{
if(s[i])
{
lx[i]-=d;
}
}
for(i=1;i<=n;i++)
{
if(t[i])
{
ly[i]+=d;
}
else
slack[i]-=d;
}
}
void init()//初始化
{
int i,j;
memset(lef,0,sizeof(lef));
memset(ly,0,sizeof(ly));
for(i=1;i<=n;i++)
{
for(j=1,lx[i]=0;j<=n;j++)
{
lx[i]=max(lx[i],w[i][j]);//頂標初始化爲權值的最大的
}
}
}
int KM()
{
int i,j;
init();
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
slack[j]=inf;;
}///初始化鬆弛度
while(1)
{
for(j=1;j<=n;j++)
{
s[j]=t[j]=0;
}
if(dfs(i))///找到退出
break;
else
update();///更新頂標值
}
}
int result=0;
for(i=1;i<=n;i++)
{
if(lef[i]>0)
{
result+=w[lef[i]][i];///計算和()
}
}
return result;
}
int main()
{
int i,j,x,ans;
while(~scanf("%d",&n)&&n)
{
for(i=1;i<=n;i++)
{
scanf("%d",&N[i]);
}
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
scanf("%1d",&x);
x==1?w[i][j]=N[i]^N[j]:w[i][j]=0;
}
}
ans=KM();
printf("%d\n",ans);
}
return 0;
}
3.最小路徑覆蓋數=G的點數-最小路徑覆蓋中的邊數=|G|-最大匹配數;
4、最大團 = 補圖的最大獨立集
5、最小覆蓋數+最大獨立集 = 頂點數
6、在二分圖中 最小覆蓋數 = 最大匹配數
************************************更新日期2014.11.3
二、網絡流
1、最短增廣路算法(Dinic算法(白書))
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include<queue>
#include <stdio.h>
#define max(a,b) a>b?a:b
#define min(a,b) a<b?a:b
#define N 200010
#define inf 0x3f3f3f3f
using namespace std;
struct Edge
{
int from,to,cap,flow;
};
struct Dinic
{
int n,m,s,t;
vector<Edge>edges;////邊集
vector<int>G[N];///鄰接表
bool vis[N];///訪問標誌
int d[N];///距離
int cur[N];///當前討論的弧
bool bfs()///分層次得到層次圖
{
memset(vis,0,sizeof(vis));
queue<int>Q;
Q.push(s);
d[s]=0;
vis[s]=1;
while(!Q.empty())
{
int x=Q.front();
Q.pop();
for(int i=0; i<G[x].size(); i++)
{
Edge &e=edges[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to]=1;
d[e.to]=d[x]+1;
Q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x,int a)///增廣
{
if(x==t||a==0)
return a;
int flow=0,f;
for(int &i=cur[x]; i<G[x].size(); i++)
{
Edge &e=edges[G[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0)
{
e.flow+=f;
edges[G[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(!a)
break;
}
}
return flow;
}
int Maxflow(int s,int t)
{
this->s=s;
this->t=t;
int flow=0;
while(bfs())
{
memset(cur,0,sizeof(cur));
flow+=dfs(s,inf);
}
return flow;
}
void addedge(int from,int to,int cap)///加邊
{
edges.push_back((Edge)
{
from,to,cap,0
});
edges.push_back((Edge)
{
to,from,0,0
});
m=edges.size();
G[from].push_back(m-2);///正弧
G[to].push_back(m-1);///反弧
}
};
int main()
{
Dinic D;
int n,m,i,a,b,w;
while(~scanf("%d%d",&n,&m))
{
D.s=0,D.t=n+1;
for(i=1;i<=n;i++)
{
scanf("%d%d",&a,&b);
D.addedge(D.s,i,a);
D.addedge(i,D.t,b);
}
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&w);
D.addedge(a,b,w);
D.addedge(b,a,w);
}
cout<<D.Maxflow(D.s,D.t)<<endl;
}
return 0;
}
三、圖的連通性(強連通分量)
#include<iostream>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#define N 10010
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
using namespace std;
vector<int> G[N];
int dfn[N],low[N],st[N];///inst[N];
int t=0,top=0;
bool inst[N];
int scc_num;
void dfs(int x)
{
low[x]=dfn[x]=(t);
t++;
st[top++]=x;
inst[x]=true;
for(int i=0;i<G[x].size();i++)
{
int j=G[x][i];
if(!dfn[j])
{
dfs(j);
low[x]=min(low[x],low[j]);
}
else if(inst[x])
{
low[x]=min(low[x],dfn[j]);
}
}
if(low[x]==dfn[x])
{
scc_num++;
while(top)
{
int j=st[top];
top--;
inst[j]=false;
if(j==x)
break;
}
}
}
void tarjan(int n)
{
scc_num=top=t=0;
memset(dfn,0,sizeof(dfn));
for(int i=1;i<=n;i++)
{
if(!dfn[i])
dfs(i);
}
}
int main()
{
int n,m,i,a,b;
while(~scanf("%d%d",&n,&m)&&(n||m))
{
for(i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
G[a].push_back(b);
}
tarjan(n);
if(scc_num<=1)
printf("Yes\n");
else
printf("No\n");
for(i=0;i<=n;i++)
G[i].clear();
}
return 0;
}
四、數論
1、大整數取模(a*b mod m)
時間複雜度:O(log n)
代碼:
LL mul_mod(LL a,LL b,LL m)
{
LL s=0;
while(b)//乘法變加法
{
if(b&1)
s=(s+a)%m;
a=(a*2)%m;
b=b>>1;
}
return s<0?s+m:s;
}
2、快速冪取模(a^b mod m)
時間複雜度:O(log n)
代碼:
LL pow_mod(LL a,LL b,LL m)
{
LL res,t;
res=1%m;
t=a%m;
while(b)
{
if(b&1)
{
res=mul_mod(res,t,m);///避免超 long long
}
t=mul_mod(t,t,m);
b>>=1;
}
return res<0?(res+m):res;
}
3、擴展歐幾里得算法(a*x+b*y=gcd(a,b))
時間複雜度:O(logb)
代碼:
LL ext_gcd(LL a,LL b,LL &x,LL &y)
{
if(!b)
{
x=1,y=0;
return a;
}
LL g=ext_gcd(b,a%b,x,y);
LL t=x;
x=y;
y=t-(a/b)*y;
return g;
}
矩陣快速冪:
<pre name="code" class="cpp">struct Matrix
{
long long int m[N][N];
friend Matrix operator*(Matrix &a,Matrix &b)
{
int i,j,k;
Matrix c;
memset(c.m,0,sizeof(c.m));
for(i=0; i<N; i++)
{
for(j=0; j<N; j++)
{
for(k=0; k<N; k++)
{
if(!b.m[k][j]||!b.m[i][k])continue;
c.m[i][j]+=(a.m[i][k]*b.m[k][j]+mod)%mod;
c.m[i][j]%=mod;
}
}
}
return c;
}
friend Matrix operator^(Matrix a,int n)
{
Matrix b;
memset(b.m,0,sizeof(b.m));
for(int i=0; i<N; i++)b.m[i][i]=1;
while(n)
{
if(n&1) b=b*a;
a=a*a;
n/=2;
}
return b;
}
};
五、最短路
1、floyd 算法(鄰接矩陣)
struct Edge
{
int from,to,w;
};
struct Floyd
{
int n,m;
vector<Edge>edges;
vector<int>G[N];
int d[N][N];
void init(int n)
{
this->n=n;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i==j)
d[i][j]=0;
else
d[i][j]=inf;
}
}
}
void addedges(int from,int to,int w)
{
if(d[from][to]==inf)
d[from][to]=w;
else
d[from][to]=min(d[from][to],w);
}
void floyd()
{
int k,j,i;
for(k=0; k<n; k++)
{
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
{
if(d[i][j]>(d[i][k]+d[k][j]))
{
d[i][j]=d[i][k]+d[k][j];
}
}
}
}
}
};
六、基礎幾何
#include <iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<vector>
#include<stdlib.h>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<math.h>
#define inf 0x3f3f3f3f
#define eps 1e-5
#define max(a,b) (a)>(b)?(a):(b)
#define min(a,b) (a)<(b)?(a):(b)
using namespace std;
int dcmp(double x)///精度比較函數
{
if(fabs(x)<eps)
return 0;
return x<0?-1:1;
}
struct Point
{
double x,y;
Point(double x=0,double y=0):x(x),y(y) {}//構造函數
friend istream& operator >>(istream &in,Point &A)///輸入點函數重載
{
/// double x,y;
scanf("%lf%lf",&A.x,&A.y);
return in;
}
friend Point operator +(Point A,Point B)//點加法
{
return Point(A.x+B.x,A.y+B.y);
}
friend Point operator -(Point A,Point B)//點減法
{
return Point(A.x-B.x,A.y-B.y);
}
friend Point operator *(Point A,double p)//點乘數
{
return Point(A.x*p,A.y*p);
}
friend Point operator /(Point A,double p)//點除數
{
return Point(A.x/p,A.y/p);
}
friend bool operator <(const Point &a,const Point &b)//點比較
{
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
friend bool operator == (const Point &a,const Point &b)///判斷點相等
{
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
};
typedef Point Vector;
double Dot(Vector A,Vector B)///點乘
{
return A.x*B.x+A.y*B.y;
}
double Length(Vector A)///求向量的模
{
return sqrt(Dot(A,A));
}
double Angle(Vector A,Vector B)///求向量的夾角
{
return acos(Dot(A,B)/Length(A)/Length(B));
}
double Cross(Vector A,Vector B)///叉乘
{
return A.x*B.y-A.y*B.x;
}
double Area2(Point A,Point B,Point C)///有向面積*2
{
return Cross(B-A,C-A);
}
Vector Rotate(Vector A,double rad)//向量旋轉
{
return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)///求兩直線的交點(法向式方程)
{
Vector u=P-Q;
double t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
Point getD(Point A,Point B,Point C)///uva11178
{
Vector v1=C-B;
double a1=Angle(A-B,v1);
v1=Rotate(v1,a1/3);
Vector v2=B-C;
double a2=Angle(A-C,v2);
v2=Rotate(v2,-a2/3);
return GetLineIntersection(B,v1,C,v2);
}
int main()
{
int t;
while(~scanf("%d",&t))
{
while(t--)
{
Point A,B,C,D,E,F;
cin>>A>>B>>C;
D=getD(A,B,C);
E=getD(B,C,A);
F=getD(C,A,B);
printf("%.6f %.6f %.6f %.6f %.6f %.6f\n",D.x,D.y,E.x,E.y,F.x,F.y);
}
}
return 0;
}