您的位置:首页 > 其它

[TJOI2015]线性代数

2017-08-30 19:49 357 查看

 

OJ题号:
BZOJ3996

题目大意:
  给定一个矩阵$B_{nn}$,矩阵$C_{1n}$,存在一个01矩阵$A_{1,n}$使得$d=(A\times B-c)\times A^\mathsf{T}$最大,求$d$的最大值。

思路:
  化简以后可以得到$d=\displaystyle{\sum_{i=1}^{n}\sum_{j=1}^{n}}a_ia_jb_{ij}-\displaystyle{\sum_{i=1}^{n}}a_ic_i$。
  由于$A$是一个01矩阵,因此我们可以将这题转化为“取物品”的问题。
  已知有$n$个物品,取第$i$个有$c_i$的收益,若同时取$i$和$j$则有$c_i+c_j+b_{ij}$的收益,求最大收益。
  我们先设置超级源汇$S$和$T$,然后对于所有的$(i,j)$,连一条从$S$到$(i,j)$的容量为$b_{ij}$的边,再分别连从$(i,j)$到$i$和$j$的容量为$\infty$的边。
  对于每一个$i$,连一条从$i$到$T$的容量为$c_i$的边。
  然后求出最小割$f$,则$d=\displaystyle{\sum_{i=1}^n\sum_{j=1}^n}b_{ij}-f$。
  然后用Edmonds-Karp算法写了一遍发现TLE了,改成用Dinic加上当前弧优化就能AC了。

#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
inline int getint() {
char ch;
while(!isdigit(ch=getchar()));
int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int inf=0x7fffffff;
const int E=1501000,V=250502;
int s,t;
struct Edge {
int from,to,remain;
};
int sz=0;
Edge e[E];
std::vector<int> g[V];
inline void add_edge(const int u,const int v,const int w) {
e[sz]=(Edge){u,v,w};
g[u].push_back(sz);
sz++;
}
int lev[V];
inline void bfs() {
for(int i=1;i<=t;i++) lev[i]=inf;
lev[s]=0;
std::queue<int> q;
q.push(s);
while(!q.empty()) {
int x=q.front();
q.pop();
for(unsigned i=0;i<g[x].size();i++) {
Edge &y=e[g[x][i]];
if(y.remain&&lev[y.to]==inf) {
lev[y.to]=lev[x]+1;
q.push(y.to);
}
}
}
}
unsigned cur[V]={0};
int dfs(const int x,const int flow) {
if(x==t) return flow;
for(unsigned &i=cur[x];i<g[x].size();i++) {
Edge y=e[g[x][i]];
if(y.remain&&lev[x]<lev[y.to]) {
int f=dfs(y.to,std::min(flow,y.remain));
if(f) {
e[g[x][i]].remain-=f;
e[g[x][i]^1].remain+=f;
return f;
}
}
}
return 0;
}
inline int Dinic() {
int maxflow=0;
for(;;) {
bfs();
if(lev[t]==inf) break;
while(int flow=dfs(s,inf)) {
maxflow+=flow;
}
}
return maxflow;
}
int main() {
int n=getint();
s=0,t=n*(n+1)+1;
int ans=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
int id=i*n+j;
int w=getint();
ans+=w;
add_edge(s,id,w);
add_edge(id,s,0);
add_edge(id,i,inf);
add_edge(i,id,0);
add_edge(id,j,inf);
add_edge(j,id,0);
}
}
for(int i=1;i<=n;i++) {
add_edge(i,t,getint());
add_edge(t,i,0);
}
printf("%d\n",ans-Dinic());
return 0;
}

Edmonds-Karp的TLE代码:

#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
inline int getint() {
char ch;
while(!isdigit(ch=getchar()));
int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int inf=0x7fffffff;
const int E=1501000,V=250502;
int s,t;
struct Edge {
int from,to,remain;
};
int sz=0;
Edge e[E];
std::vector<int> g[V];
inline void add_edge(const int u,const int v,const int w) {
e[sz]=(Edge){u,v,w};
g[u].push_back(sz);
sz++;
}
int a[V],p[V];
inline int Augment() {
memset(a,0,sizeof a);
a[s]=inf;
std::queue<int> q;
q.push(s);
while(!q.empty()) {
int x=q.front();
q.pop();
for(unsigned i=0;i<g[x].size();i++) {
Edge &y=e[g[x][i]];
if(y.remain&&!a[y.to]) {
a[y.to]=std::min(a[x],y.remain);
p[y.to]=g[x][i];
q.push(y.to);
}
}
if(a[t]) break;
}
return a[t];
}
inline int EdmondsKarp() {
int maxflow=0;
while(int flow=Augment()) {
for(int i=t;i!=s;i=e[p[i]].from) {
e[p[i]].remain-=flow;
e[p[i]^1].remain+=flow;
}
maxflow+=flow;
}
return maxflow;
}
int main() {
int n=getint();
s=0,t=n*(n+1)+1;
int ans=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) {
int id=i*n+j;
int w=getint();
ans+=w;
add_edge(s,id,w);
add_edge(id,s,0);
add_edge(id,i,inf);
add_edge(i,id,0);
add_edge(id,j,inf);
add_edge(j,id,0);
}
}
for(int i=1;i<=n;i++) {
add_edge(i,t,getint());
add_edge(t,i,0);
}
printf("%d\n",ans-EdmondsKarp());
return 0;
}
View Code

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: