#include <algorithm>  
#include <iostream>  
#include <sstream>  
#include <string>  
#include <cstring>
#include <vector>  
#include <queue>  
#include <set>  
#include <map>  
#include <cstdio>  
#include <cstdlib>  
#include <cctype>  
#include <cmath>  
#include <list>  
#include <cassert>
#include <ctime>
#include <climits>
using namespace std;  

#define PB push_back  
#define MP make_pair  
#define SZ(v) ((int)(v).size())  
#define FOR(i,a,b) for(int i=(a);i<(b);++i)  
#define REP(i,n) FOR(i,0,n)  
#define FORE(i,a,b) for(int i=(a);i<=(b);++i)  
#define REPE(i,n) FORE(i,0,n)  
#define FORSZ(i,a,v) FOR(i,a,SZ(v))  
#define REPSZ(i,v) REP(i,SZ(v))  
typedef long long ll;
typedef unsigned long long ull;
ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b); }

const int MAXN=300;
const int MOD=1000000007;
void inc(int &a,int b) { if((a+=b)>=MOD) a-=MOD; }

int n;
int a[2*MAXN];

bool used[2*MAXN];
int avail[2*MAXN],navail;
int nfree;
int cons[MAXN],ncons;

int vals[2*MAXN],nvals;
int dp[2*MAXN+1][MAXN+1][MAXN+1];


int solve() {
	REP(i,2*n) used[i]=false;
	REP(i,2*n) if(a[i]!=-1) used[a[i]]=true;
	navail=0; REP(i,2*n) if(!used[i]) avail[navail++]=i;
	nfree=0,ncons=0;
	REP(i,n) {
		int x=a[2*i],y=a[2*i+1];
		if(x==-1&&y!=-1) swap(x,y);
		if(x==-1) ++nfree; else if(y==-1) cons[ncons++]=x;
	}
	nvals=0; REP(i,navail) vals[nvals++]=avail[i]; REP(i,ncons) vals[nvals++]=cons[i]; sort(vals,vals+nvals);
	//printf("avail:"); REP(i,navail) printf(" %d",avail[i]+1); puts("");
	//printf("nfree=%d\n",nfree);
	//printf("cons:"); REP(i,ncons) printf(" %d",cons[i]+1); puts("");
	//printf("vals:"); REP(i,nvals) printf(" %d",vals[i]+1); puts("");

	int nusedsofar=0,nunusedsofar=0; memset(dp,0,sizeof(dp)); inc(dp[0][0][0],1);
	REP(i,nvals) {
			REPE(j,n) REPE(k,nfree) if(dp[i][j][k]!=0) { // j=ntoskip,k=nfreedone
			// ntoskip=0, ntooverwrite=0, k=0; invariant hypotheses: ntoskip-ntooverwrite-#usedsofar+#unusedsofar-2*k=0 -> ntooverwrite=ntoskip+#unusedsofar-#usedsofar-2*k
			int ntooverwrite=j+nunusedsofar-nusedsofar-2*k;
			//printf("dp[%d][%d][%d]=%d (ntooverwrite=%d)\n",i,j,k,dp[i][j][k],ntooverwrite);
			if(!used[vals[i]]) {
				// skip it (--ntoskip)
				if(j>0) inc(dp[i+1][j-1][k],dp[i][j][k]);
				// use for constrained (++ntooverwrite)
				inc(dp[i+1][j][k],dp[i][j][k]);
				// use for free (++nfreedone,++ntoskip)
				if(k<nfree) inc(dp[i+1][j+1][k+1],dp[i][j][k]);
			} else {
				// keep it (++ntoskip)
				if(j<n) inc(dp[i+1][j+1][k],dp[i][j][k]);
				// overwrite it (--ntooverwrite)
				if(ntooverwrite>0) inc(dp[i+1][j][k],(ll)ntooverwrite*dp[i][j][k]%MOD);
			}
		}
		nusedsofar+=used[vals[i]]?1:0;
		nunusedsofar+=used[vals[i]]?0:1;
	}
	int ret=dp[nvals][0][nfree];
	FORE(i,1,nfree) ret=(ll)ret*i%MOD;
	return ret;
}

void run() {
	scanf("%d",&n);
	REP(i,2*n) scanf("%d",&a[i]);
	REP(i,2*n) if(a[i]!=-1) --a[i];
	printf("%d\n",solve());
}

ll bfsolve() {
	REP(i,2*n) used[i]=false;
	REP(i,2*n) if(a[i]!=-1) used[a[i]]=true;
	navail=0; REP(i,2*n) if(!used[i]) avail[navail++]=i;
	set<vector<int>> seen;
	do {
		vector<int> cur(n);
		int at=0; REP(i,n) { int x=a[2*i+0]; if(x==-1) x=avail[at++]; int y=a[2*i+1]; if(y==-1) y=avail[at++]; cur[i]=min(x,y); }
		seen.insert(cur);
	} while(next_permutation(avail,avail+navail));
	return SZ(seen);
}

void stress() {
	REP(rep,10000) {
		n=6;
		REP(i,2*n) a[i]=i; REP(i,2*n) swap(a[i],a[rand()%(i+1)]); REP(i,2*n) if(rand()%2==0) a[i]=-1;
		ll have=solve();
		ll want=bfsolve();
		if(have==want) { printf("."); continue; }
		printf("have=%lld want=%lld\n",have,want);
		printf("%d\n",n); REP(i,2*n) { if(i!=0) printf(" "); printf("%d",a[i]==-1?-1:a[i]+1); } puts("");
		return;
	}
}

int main() {
	run();
	//stress();
	return 0;
}


Measured memory_bytes: 212992